aboutsummaryrefslogtreecommitdiff
path: root/gcc/lra-constraints.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/lra-constraints.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/lra-constraints.c')
-rw-r--r--gcc/lra-constraints.c7380
1 files changed, 0 insertions, 7380 deletions
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
deleted file mode 100644
index 9a333a8..0000000
--- a/gcc/lra-constraints.c
+++ /dev/null
@@ -1,7380 +0,0 @@
-/* Code for RTL transformations to satisfy insn constraints.
- Copyright (C) 2010-2022 Free Software Foundation, Inc.
- Contributed by Vladimir Makarov <vmakarov@redhat.com>.
-
- This file is part of GCC.
-
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
-
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
-
-
-/* This file contains code for 3 passes: constraint pass,
- inheritance/split pass, and pass for undoing failed inheritance and
- split.
-
- The major goal of constraint pass is to transform RTL to satisfy
- insn and address constraints by:
- o choosing insn alternatives;
- o generating *reload insns* (or reloads in brief) and *reload
- pseudos* which will get necessary hard registers later;
- o substituting pseudos with equivalent values and removing the
- instructions that initialized those pseudos.
-
- The constraint pass has biggest and most complicated code in LRA.
- There are a lot of important details like:
- o reuse of input reload pseudos to simplify reload pseudo
- allocations;
- o some heuristics to choose insn alternative to improve the
- inheritance;
- o early clobbers etc.
-
- The pass is mimicking former reload pass in alternative choosing
- because the reload pass is oriented to current machine description
- model. It might be changed if the machine description model is
- changed.
-
- There is special code for preventing all LRA and this pass cycling
- in case of bugs.
-
- On the first iteration of the pass we process every instruction and
- choose an alternative for each one. On subsequent iterations we try
- to avoid reprocessing instructions if we can be sure that the old
- choice is still valid.
-
- The inheritance/spilt pass is to transform code to achieve
- ineheritance and live range splitting. It is done on backward
- traversal of EBBs.
-
- The inheritance optimization goal is to reuse values in hard
- registers. There is analogous optimization in old reload pass. The
- inheritance is achieved by following transformation:
-
- reload_p1 <- p reload_p1 <- p
- ... new_p <- reload_p1
- ... => ...
- reload_p2 <- p reload_p2 <- new_p
-
- where p is spilled and not changed between the insns. Reload_p1 is
- also called *original pseudo* and new_p is called *inheritance
- pseudo*.
-
- The subsequent assignment pass will try to assign the same (or
- another if it is not possible) hard register to new_p as to
- reload_p1 or reload_p2.
-
- If the assignment pass fails to assign a hard register to new_p,
- this file will undo the inheritance and restore the original code.
- This is because implementing the above sequence with a spilled
- new_p would make the code much worse. The inheritance is done in
- EBB scope. The above is just a simplified example to get an idea
- of the inheritance as the inheritance is also done for non-reload
- insns.
-
- Splitting (transformation) is also done in EBB scope on the same
- pass as the inheritance:
-
- r <- ... or ... <- r r <- ... or ... <- r
- ... s <- r (new insn -- save)
- ... =>
- ... r <- s (new insn -- restore)
- ... <- r ... <- r
-
- The *split pseudo* s is assigned to the hard register of the
- original pseudo or hard register r.
-
- Splitting is done:
- o In EBBs with high register pressure for global pseudos (living
- in at least 2 BBs) and assigned to hard registers when there
- are more one reloads needing the hard registers;
- o for pseudos needing save/restore code around calls.
-
- If the split pseudo still has the same hard register as the
- original pseudo after the subsequent assignment pass or the
- original pseudo was split, the opposite transformation is done on
- the same pass for undoing inheritance. */
-
-#undef REG_OK_STRICT
-
-#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 "expmed.h"
-#include "optabs.h"
-#include "regs.h"
-#include "ira.h"
-#include "recog.h"
-#include "output.h"
-#include "addresses.h"
-#include "expr.h"
-#include "cfgrtl.h"
-#include "rtl-error.h"
-#include "lra.h"
-#include "lra-int.h"
-#include "print-rtl.h"
-#include "function-abi.h"
-#include "rtl-iter.h"
-
-/* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current
- insn. Remember that LRA_CURR_RELOAD_NUM is the number of emitted
- reload insns. */
-static int bb_reload_num;
-
-/* The current insn being processed and corresponding its single set
- (NULL otherwise), its data (basic block, the insn data, the insn
- static data, and the mode of each operand). */
-static rtx_insn *curr_insn;
-static rtx curr_insn_set;
-static basic_block curr_bb;
-static lra_insn_recog_data_t curr_id;
-static struct lra_static_insn_data *curr_static_id;
-static machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
-/* Mode of the register substituted by its equivalence with VOIDmode
- (e.g. constant) and whose subreg is given operand of the current
- insn. VOIDmode in all other cases. */
-static machine_mode original_subreg_reg_mode[MAX_RECOG_OPERANDS];
-
-
-
-/* Start numbers for new registers and insns at the current constraints
- pass start. */
-static int new_regno_start;
-static int new_insn_uid_start;
-
-/* If LOC is nonnull, strip any outer subreg from it. */
-static inline rtx *
-strip_subreg (rtx *loc)
-{
- return loc && GET_CODE (*loc) == SUBREG ? &SUBREG_REG (*loc) : loc;
-}
-
-/* Return hard regno of REGNO or if it is was not assigned to a hard
- register, use a hard register from its allocno class. */
-static int
-get_try_hard_regno (int regno)
-{
- int hard_regno;
- enum reg_class rclass;
-
- if ((hard_regno = regno) >= FIRST_PSEUDO_REGISTER)
- hard_regno = lra_get_regno_hard_regno (regno);
- if (hard_regno >= 0)
- return hard_regno;
- rclass = lra_get_allocno_class (regno);
- if (rclass == NO_REGS)
- return -1;
- return ira_class_hard_regs[rclass][0];
-}
-
-/* Return the hard regno of X after removing its subreg. If X is not
- a register or a subreg of a register, return -1. If X is a pseudo,
- use its assignment. If FINAL_P return the final hard regno which will
- be after elimination. */
-static int
-get_hard_regno (rtx x, bool final_p)
-{
- rtx reg;
- int hard_regno;
-
- reg = x;
- if (SUBREG_P (x))
- reg = SUBREG_REG (x);
- if (! REG_P (reg))
- return -1;
- if (! HARD_REGISTER_NUM_P (hard_regno = REGNO (reg)))
- hard_regno = lra_get_regno_hard_regno (hard_regno);
- if (hard_regno < 0)
- return -1;
- if (final_p)
- hard_regno = lra_get_elimination_hard_regno (hard_regno);
- if (SUBREG_P (x))
- hard_regno += subreg_regno_offset (hard_regno, GET_MODE (reg),
- SUBREG_BYTE (x), GET_MODE (x));
- return hard_regno;
-}
-
-/* If REGNO is a hard register or has been allocated a hard register,
- return the class of that register. If REGNO is a reload pseudo
- created by the current constraints pass, return its allocno class.
- Return NO_REGS otherwise. */
-static enum reg_class
-get_reg_class (int regno)
-{
- int hard_regno;
-
- if (! HARD_REGISTER_NUM_P (hard_regno = regno))
- hard_regno = lra_get_regno_hard_regno (regno);
- if (hard_regno >= 0)
- {
- hard_regno = lra_get_elimination_hard_regno (hard_regno);
- return REGNO_REG_CLASS (hard_regno);
- }
- if (regno >= new_regno_start)
- return lra_get_allocno_class (regno);
- return NO_REGS;
-}
-
-/* Return true if REG satisfies (or will satisfy) reg class constraint
- CL. Use elimination first if REG is a hard register. If REG is a
- reload pseudo created by this constraints pass, assume that it will
- be allocated a hard register from its allocno class, but allow that
- class to be narrowed to CL if it is currently a superset of CL and
- if either:
-
- - ALLOW_ALL_RELOAD_CLASS_CHANGES_P is true or
- - the instruction we're processing is not a reload move.
-
- If NEW_CLASS is nonnull, set *NEW_CLASS to the new allocno class of
- REGNO (reg), or NO_REGS if no change in its class was needed. */
-static bool
-in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class,
- bool allow_all_reload_class_changes_p = false)
-{
- enum reg_class rclass, common_class;
- machine_mode reg_mode;
- rtx src;
- int class_size, hard_regno, nregs, i, j;
- int regno = REGNO (reg);
-
- if (new_class != NULL)
- *new_class = NO_REGS;
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- rtx final_reg = reg;
- rtx *final_loc = &final_reg;
-
- lra_eliminate_reg_if_possible (final_loc);
- return TEST_HARD_REG_BIT (reg_class_contents[cl], REGNO (*final_loc));
- }
- reg_mode = GET_MODE (reg);
- rclass = get_reg_class (regno);
- src = curr_insn_set != NULL ? SET_SRC (curr_insn_set) : NULL;
- if (regno < new_regno_start
- /* Do not allow the constraints for reload instructions to
- influence the classes of new pseudos. These reloads are
- typically moves that have many alternatives, and restricting
- reload pseudos for one alternative may lead to situations
- where other reload pseudos are no longer allocatable. */
- || (!allow_all_reload_class_changes_p
- && INSN_UID (curr_insn) >= new_insn_uid_start
- && src != NULL
- && ((REG_P (src) || MEM_P (src))
- || (GET_CODE (src) == SUBREG
- && (REG_P (SUBREG_REG (src)) || MEM_P (SUBREG_REG (src)))))))
- /* When we don't know what class will be used finally for reload
- pseudos, we use ALL_REGS. */
- return ((regno >= new_regno_start && rclass == ALL_REGS)
- || (rclass != NO_REGS && ira_class_subset_p[rclass][cl]
- && ! hard_reg_set_subset_p (reg_class_contents[cl],
- lra_no_alloc_regs)));
- else
- {
- common_class = ira_reg_class_subset[rclass][cl];
- if (new_class != NULL)
- *new_class = common_class;
- if (hard_reg_set_subset_p (reg_class_contents[common_class],
- lra_no_alloc_regs))
- return false;
- /* Check that there are enough allocatable regs. */
- class_size = ira_class_hard_regs_num[common_class];
- for (i = 0; i < class_size; i++)
- {
- hard_regno = ira_class_hard_regs[common_class][i];
- nregs = hard_regno_nregs (hard_regno, reg_mode);
- if (nregs == 1)
- return true;
- for (j = 0; j < nregs; j++)
- if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j)
- || ! TEST_HARD_REG_BIT (reg_class_contents[common_class],
- hard_regno + j))
- break;
- if (j >= nregs)
- return true;
- }
- return false;
- }
-}
-
-/* Return true if REGNO satisfies a memory constraint. */
-static bool
-in_mem_p (int regno)
-{
- return get_reg_class (regno) == NO_REGS;
-}
-
-/* Return 1 if ADDR is a valid memory address for mode MODE in address
- space AS, and check that each pseudo has the proper kind of hard
- reg. */
-static int
-valid_address_p (machine_mode mode ATTRIBUTE_UNUSED,
- rtx addr, addr_space_t as)
-{
-#ifdef GO_IF_LEGITIMATE_ADDRESS
- lra_assert (ADDR_SPACE_GENERIC_P (as));
- GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
- return 0;
-
- win:
- return 1;
-#else
- return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
-#endif
-}
-
-namespace {
- /* Temporarily eliminates registers in an address (for the lifetime of
- the object). */
- class address_eliminator {
- public:
- address_eliminator (struct address_info *ad);
- ~address_eliminator ();
-
- private:
- struct address_info *m_ad;
- rtx *m_base_loc;
- rtx m_base_reg;
- rtx *m_index_loc;
- rtx m_index_reg;
- };
-}
-
-address_eliminator::address_eliminator (struct address_info *ad)
- : m_ad (ad),
- m_base_loc (strip_subreg (ad->base_term)),
- m_base_reg (NULL_RTX),
- m_index_loc (strip_subreg (ad->index_term)),
- m_index_reg (NULL_RTX)
-{
- if (m_base_loc != NULL)
- {
- m_base_reg = *m_base_loc;
- /* If we have non-legitimate address which is decomposed not in
- the way we expected, don't do elimination here. In such case
- the address will be reloaded and elimination will be done in
- reload insn finally. */
- if (REG_P (m_base_reg))
- lra_eliminate_reg_if_possible (m_base_loc);
- if (m_ad->base_term2 != NULL)
- *m_ad->base_term2 = *m_ad->base_term;
- }
- if (m_index_loc != NULL)
- {
- m_index_reg = *m_index_loc;
- if (REG_P (m_index_reg))
- lra_eliminate_reg_if_possible (m_index_loc);
- }
-}
-
-address_eliminator::~address_eliminator ()
-{
- if (m_base_loc && *m_base_loc != m_base_reg)
- {
- *m_base_loc = m_base_reg;
- if (m_ad->base_term2 != NULL)
- *m_ad->base_term2 = *m_ad->base_term;
- }
- if (m_index_loc && *m_index_loc != m_index_reg)
- *m_index_loc = m_index_reg;
-}
-
-/* Return true if the eliminated form of AD is a legitimate target address.
- If OP is a MEM, AD is the address within OP, otherwise OP should be
- ignored. CONSTRAINT is one constraint that the operand may need
- to meet. */
-static bool
-valid_address_p (rtx op, struct address_info *ad,
- enum constraint_num constraint)
-{
- address_eliminator eliminator (ad);
-
- /* Allow a memory OP if it matches CONSTRAINT, even if CONSTRAINT is more
- forgiving than "m".
- Need to extract memory from op for special memory constraint,
- i.e. bcst_mem_operand in i386 backend. */
- if (MEM_P (extract_mem_from_operand (op))
- && insn_extra_relaxed_memory_constraint (constraint)
- && constraint_satisfied_p (op, constraint))
- return true;
-
- return valid_address_p (ad->mode, *ad->outer, ad->as);
-}
-
-/* For special_memory_operand, it could be false for MEM_P (op),
- i.e. bcst_mem_operand in i386 backend.
- Extract and return real memory operand or op. */
-rtx
-extract_mem_from_operand (rtx op)
-{
- for (rtx x = op;; x = XEXP (x, 0))
- {
- if (MEM_P (x))
- return x;
- if (GET_RTX_LENGTH (GET_CODE (x)) != 1
- || GET_RTX_FORMAT (GET_CODE (x))[0] != 'e')
- break;
- }
- return op;
-}
-
-/* Return true if the eliminated form of memory reference OP satisfies
- extra (special) memory constraint CONSTRAINT. */
-static bool
-satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
-{
- struct address_info ad;
- rtx mem = extract_mem_from_operand (op);
- if (!MEM_P (mem))
- return false;
-
- decompose_mem_address (&ad, mem);
- address_eliminator eliminator (&ad);
- return constraint_satisfied_p (op, constraint);
-}
-
-/* Return true if the eliminated form of address AD satisfies extra
- address constraint CONSTRAINT. */
-static bool
-satisfies_address_constraint_p (struct address_info *ad,
- enum constraint_num constraint)
-{
- address_eliminator eliminator (ad);
- return constraint_satisfied_p (*ad->outer, constraint);
-}
-
-/* Return true if the eliminated form of address OP satisfies extra
- address constraint CONSTRAINT. */
-static bool
-satisfies_address_constraint_p (rtx op, enum constraint_num constraint)
-{
- struct address_info ad;
-
- decompose_lea_address (&ad, &op);
- return satisfies_address_constraint_p (&ad, constraint);
-}
-
-/* Initiate equivalences for LRA. As we keep original equivalences
- before any elimination, we need to make copies otherwise any change
- in insns might change the equivalences. */
-void
-lra_init_equiv (void)
-{
- ira_expand_reg_equiv ();
- for (int i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++)
- {
- rtx res;
-
- if ((res = ira_reg_equiv[i].memory) != NULL_RTX)
- ira_reg_equiv[i].memory = copy_rtx (res);
- if ((res = ira_reg_equiv[i].invariant) != NULL_RTX)
- ira_reg_equiv[i].invariant = copy_rtx (res);
- }
-}
-
-static rtx loc_equivalence_callback (rtx, const_rtx, void *);
-
-/* Update equivalence for REGNO. We need to this as the equivalence
- might contain other pseudos which are changed by their
- equivalences. */
-static void
-update_equiv (int regno)
-{
- rtx x;
-
- if ((x = ira_reg_equiv[regno].memory) != NULL_RTX)
- ira_reg_equiv[regno].memory
- = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback,
- NULL_RTX);
- if ((x = ira_reg_equiv[regno].invariant) != NULL_RTX)
- ira_reg_equiv[regno].invariant
- = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback,
- NULL_RTX);
-}
-
-/* If we have decided to substitute X with another value, return that
- value, otherwise return X. */
-static rtx
-get_equiv (rtx x)
-{
- int regno;
- rtx res;
-
- if (! REG_P (x) || (regno = REGNO (x)) < FIRST_PSEUDO_REGISTER
- || ! ira_reg_equiv[regno].defined_p
- || ! ira_reg_equiv[regno].profitable_p
- || lra_get_regno_hard_regno (regno) >= 0)
- return x;
- if ((res = ira_reg_equiv[regno].memory) != NULL_RTX)
- {
- if (targetm.cannot_substitute_mem_equiv_p (res))
- return x;
- return res;
- }
- if ((res = ira_reg_equiv[regno].constant) != NULL_RTX)
- return res;
- if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX)
- return res;
- gcc_unreachable ();
-}
-
-/* If we have decided to substitute X with the equivalent value,
- return that value after elimination for INSN, otherwise return
- X. */
-static rtx
-get_equiv_with_elimination (rtx x, rtx_insn *insn)
-{
- rtx res = get_equiv (x);
-
- if (x == res || CONSTANT_P (res))
- return res;
- return lra_eliminate_regs_1 (insn, res, GET_MODE (res),
- false, false, 0, true);
-}
-
-/* Set up curr_operand_mode. */
-static void
-init_curr_operand_mode (void)
-{
- int nop = curr_static_id->n_operands;
- for (int i = 0; i < nop; i++)
- {
- machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
- if (mode == VOIDmode)
- {
- /* The .md mode for address operands is the mode of the
- addressed value rather than the mode of the address itself. */
- if (curr_id->icode >= 0 && curr_static_id->operand[i].is_address)
- mode = Pmode;
- else
- mode = curr_static_id->operand[i].mode;
- }
- curr_operand_mode[i] = mode;
- }
-}
-
-
-
-/* The page contains code to reuse input reloads. */
-
-/* Structure describes input reload of the current insns. */
-struct input_reload
-{
- /* True for input reload of matched operands. */
- bool match_p;
- /* Reloaded value. */
- rtx input;
- /* Reload pseudo used. */
- rtx reg;
-};
-
-/* The number of elements in the following array. */
-static int curr_insn_input_reloads_num;
-/* Array containing info about input reloads. It is used to find the
- same input reload and reuse the reload pseudo in this case. */
-static struct input_reload curr_insn_input_reloads[LRA_MAX_INSN_RELOADS];
-
-/* Initiate data concerning reuse of input reloads for the current
- insn. */
-static void
-init_curr_insn_input_reloads (void)
-{
- curr_insn_input_reloads_num = 0;
-}
-
-/* The canonical form of an rtx inside a MEM is not necessarily the same as the
- canonical form of the rtx outside the MEM. Fix this up in the case that
- we're reloading an address (and therefore pulling it outside a MEM). */
-static rtx
-canonicalize_reload_addr (rtx addr)
-{
- subrtx_var_iterator::array_type array;
- FOR_EACH_SUBRTX_VAR (iter, array, addr, NONCONST)
- {
- rtx x = *iter;
- if (GET_CODE (x) == MULT && CONST_INT_P (XEXP (x, 1)))
- {
- const HOST_WIDE_INT ci = INTVAL (XEXP (x, 1));
- const int pwr2 = exact_log2 (ci);
- if (pwr2 > 0)
- {
- /* Rewrite this to use a shift instead, which is canonical when
- outside of a MEM. */
- PUT_CODE (x, ASHIFT);
- XEXP (x, 1) = GEN_INT (pwr2);
- }
- }
- }
-
- return addr;
-}
-
-/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse an existing
- reload pseudo. Don't reuse an existing reload pseudo if IN_SUBREG_P
- is true and the reused pseudo should be wrapped up in a SUBREG.
- The result pseudo is returned through RESULT_REG. Return TRUE if we
- created a new pseudo, FALSE if we reused an existing reload pseudo.
- Use TITLE to describe new registers for debug purposes. */
-static bool
-get_reload_reg (enum op_type type, machine_mode mode, rtx original,
- enum reg_class rclass, bool in_subreg_p,
- const char *title, rtx *result_reg)
-{
- int i, regno;
- enum reg_class new_class;
- bool unique_p = false;
-
- if (type == OP_OUT)
- {
- /* Output reload registers tend to start out with a conservative
- choice of register class. Usually this is ALL_REGS, although
- a target might narrow it (for performance reasons) through
- targetm.preferred_reload_class. It's therefore quite common
- for a reload instruction to require a more restrictive class
- than the class that was originally assigned to the reload register.
-
- In these situations, it's more efficient to refine the choice
- of register class rather than create a second reload register.
- This also helps to avoid cycling for registers that are only
- used by reload instructions. */
- if (REG_P (original)
- && (int) REGNO (original) >= new_regno_start
- && INSN_UID (curr_insn) >= new_insn_uid_start
- && in_class_p (original, rclass, &new_class, true))
- {
- unsigned int regno = REGNO (original);
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Reuse r%d for output ", regno);
- dump_value_slim (lra_dump_file, original, 1);
- }
- if (new_class != lra_get_allocno_class (regno))
- lra_change_class (regno, new_class, ", change to", false);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "\n");
- *result_reg = original;
- return false;
- }
- *result_reg
- = lra_create_new_reg_with_unique_value (mode, original, rclass, title);
- return true;
- }
- /* Prevent reuse value of expression with side effects,
- e.g. volatile memory. */
- if (! side_effects_p (original))
- for (i = 0; i < curr_insn_input_reloads_num; i++)
- {
- if (! curr_insn_input_reloads[i].match_p
- && rtx_equal_p (curr_insn_input_reloads[i].input, original)
- && in_class_p (curr_insn_input_reloads[i].reg, rclass, &new_class))
- {
- rtx reg = curr_insn_input_reloads[i].reg;
- regno = REGNO (reg);
- /* If input is equal to original and both are VOIDmode,
- GET_MODE (reg) might be still different from mode.
- Ensure we don't return *result_reg with wrong mode. */
- if (GET_MODE (reg) != mode)
- {
- if (in_subreg_p)
- continue;
- if (maybe_lt (GET_MODE_SIZE (GET_MODE (reg)),
- GET_MODE_SIZE (mode)))
- continue;
- reg = lowpart_subreg (mode, reg, GET_MODE (reg));
- if (reg == NULL_RTX || GET_CODE (reg) != SUBREG)
- continue;
- }
- *result_reg = reg;
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Reuse r%d for reload ", regno);
- dump_value_slim (lra_dump_file, original, 1);
- }
- if (new_class != lra_get_allocno_class (regno))
- lra_change_class (regno, new_class, ", change to", false);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "\n");
- return false;
- }
- /* If we have an input reload with a different mode, make sure it
- will get a different hard reg. */
- else if (REG_P (original)
- && REG_P (curr_insn_input_reloads[i].input)
- && REGNO (original) == REGNO (curr_insn_input_reloads[i].input)
- && (GET_MODE (original)
- != GET_MODE (curr_insn_input_reloads[i].input)))
- unique_p = true;
- }
- *result_reg = (unique_p
- ? lra_create_new_reg_with_unique_value
- : lra_create_new_reg) (mode, original, rclass, title);
- lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS);
- curr_insn_input_reloads[curr_insn_input_reloads_num].input = original;
- curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = false;
- curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = *result_reg;
- return true;
-}
-
-
-/* The page contains major code to choose the current insn alternative
- and generate reloads for it. */
-
-/* Return the offset from REGNO of the least significant register
- in (reg:MODE REGNO).
-
- This function is used to tell whether two registers satisfy
- a matching constraint. (reg:MODE1 REGNO1) matches (reg:MODE2 REGNO2) if:
-
- REGNO1 + lra_constraint_offset (REGNO1, MODE1)
- == REGNO2 + lra_constraint_offset (REGNO2, MODE2) */
-int
-lra_constraint_offset (int regno, machine_mode mode)
-{
- lra_assert (regno < FIRST_PSEUDO_REGISTER);
-
- scalar_int_mode int_mode;
- if (WORDS_BIG_ENDIAN
- && is_a <scalar_int_mode> (mode, &int_mode)
- && GET_MODE_SIZE (int_mode) > UNITS_PER_WORD)
- return hard_regno_nregs (regno, mode) - 1;
- return 0;
-}
-
-/* Like rtx_equal_p except that it allows a REG and a SUBREG to match
- if they are the same hard reg, and has special hacks for
- auto-increment and auto-decrement. This is specifically intended for
- process_alt_operands to use in determining whether two operands
- match. X is the operand whose number is the lower of the two.
-
- It is supposed that X is the output operand and Y is the input
- operand. Y_HARD_REGNO is the final hard regno of register Y or
- register in subreg Y as we know it now. Otherwise, it is a
- negative value. */
-static bool
-operands_match_p (rtx x, rtx y, int y_hard_regno)
-{
- int i;
- RTX_CODE code = GET_CODE (x);
- const char *fmt;
-
- if (x == y)
- return true;
- if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x))))
- && (REG_P (y) || (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)))))
- {
- int j;
-
- i = get_hard_regno (x, false);
- if (i < 0)
- goto slow;
-
- if ((j = y_hard_regno) < 0)
- goto slow;
-
- i += lra_constraint_offset (i, GET_MODE (x));
- j += lra_constraint_offset (j, GET_MODE (y));
-
- return i == j;
- }
-
- /* If two operands must match, because they are really a single
- operand of an assembler insn, then two post-increments are invalid
- because the assembler insn would increment only once. On the
- other hand, a post-increment matches ordinary indexing if the
- post-increment is the output operand. */
- if (code == POST_DEC || code == POST_INC || code == POST_MODIFY)
- return operands_match_p (XEXP (x, 0), y, y_hard_regno);
-
- /* Two pre-increments are invalid because the assembler insn would
- increment only once. On the other hand, a pre-increment matches
- ordinary indexing if the pre-increment is the input operand. */
- if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC
- || GET_CODE (y) == PRE_MODIFY)
- return operands_match_p (x, XEXP (y, 0), -1);
-
- slow:
-
- if (code == REG && REG_P (y))
- return REGNO (x) == REGNO (y);
-
- if (code == REG && GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))
- && x == SUBREG_REG (y))
- return true;
- if (GET_CODE (y) == REG && code == SUBREG && REG_P (SUBREG_REG (x))
- && SUBREG_REG (x) == y)
- return true;
-
- /* Now we have disposed of all the cases in which different rtx
- codes can match. */
- if (code != GET_CODE (y))
- return false;
-
- /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
- if (GET_MODE (x) != GET_MODE (y))
- return false;
-
- switch (code)
- {
- CASE_CONST_UNIQUE:
- return false;
-
- case CONST_VECTOR:
- if (!same_vector_encodings_p (x, y))
- return false;
- break;
-
- case LABEL_REF:
- return label_ref_label (x) == label_ref_label (y);
- case SYMBOL_REF:
- return XSTR (x, 0) == XSTR (y, 0);
-
- default:
- break;
- }
-
- /* Compare the elements. If any pair of corresponding elements fail
- to match, return false for the whole things. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- int val, j;
- switch (fmt[i])
- {
- case 'w':
- if (XWINT (x, i) != XWINT (y, i))
- return false;
- break;
-
- case 'i':
- if (XINT (x, i) != XINT (y, i))
- return false;
- break;
-
- case 'p':
- if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
- return false;
- break;
-
- case 'e':
- val = operands_match_p (XEXP (x, i), XEXP (y, i), -1);
- if (val == 0)
- return false;
- break;
-
- case '0':
- break;
-
- case 'E':
- if (XVECLEN (x, i) != XVECLEN (y, i))
- return false;
- for (j = XVECLEN (x, i) - 1; j >= 0; --j)
- {
- val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j), -1);
- if (val == 0)
- return false;
- }
- break;
-
- /* It is believed that rtx's at this level will never
- contain anything but integers and other rtx's, except for
- within LABEL_REFs and SYMBOL_REFs. */
- default:
- gcc_unreachable ();
- }
- }
- return true;
-}
-
-/* True if X is a constant that can be forced into the constant pool.
- MODE is the mode of the operand, or VOIDmode if not known. */
-#define CONST_POOL_OK_P(MODE, X) \
- ((MODE) != VOIDmode \
- && CONSTANT_P (X) \
- && GET_CODE (X) != HIGH \
- && GET_MODE_SIZE (MODE).is_constant () \
- && !targetm.cannot_force_const_mem (MODE, X))
-
-/* True if C is a non-empty register class that has too few registers
- to be safely used as a reload target class. */
-#define SMALL_REGISTER_CLASS_P(C) \
- (ira_class_hard_regs_num [(C)] == 1 \
- || (ira_class_hard_regs_num [(C)] >= 1 \
- && targetm.class_likely_spilled_p (C)))
-
-/* If REG is a reload pseudo, try to make its class satisfying CL. */
-static void
-narrow_reload_pseudo_class (rtx reg, enum reg_class cl)
-{
- enum reg_class rclass;
-
- /* Do not make more accurate class from reloads generated. They are
- mostly moves with a lot of constraints. Making more accurate
- class may results in very narrow class and impossibility of find
- registers for several reloads of one insn. */
- if (INSN_UID (curr_insn) >= new_insn_uid_start)
- return;
- if (GET_CODE (reg) == SUBREG)
- reg = SUBREG_REG (reg);
- if (! REG_P (reg) || (int) REGNO (reg) < new_regno_start)
- return;
- if (in_class_p (reg, cl, &rclass) && rclass != cl)
- lra_change_class (REGNO (reg), rclass, " Change to", true);
-}
-
-/* Searches X for any reference to a reg with the same value as REGNO,
- returning the rtx of the reference found if any. Otherwise,
- returns NULL_RTX. */
-static rtx
-regno_val_use_in (unsigned int regno, rtx x)
-{
- const char *fmt;
- int i, j;
- rtx tem;
-
- if (REG_P (x) && lra_reg_info[REGNO (x)].val == lra_reg_info[regno].val)
- return x;
-
- fmt = GET_RTX_FORMAT (GET_CODE (x));
- for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if ((tem = regno_val_use_in (regno, XEXP (x, i))))
- return tem;
- }
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if ((tem = regno_val_use_in (regno , XVECEXP (x, i, j))))
- return tem;
- }
-
- return NULL_RTX;
-}
-
-/* Return true if all current insn non-output operands except INS (it
- has a negaitve end marker) do not use pseudos with the same value
- as REGNO. */
-static bool
-check_conflict_input_operands (int regno, signed char *ins)
-{
- int in;
- int n_operands = curr_static_id->n_operands;
-
- for (int nop = 0; nop < n_operands; nop++)
- if (! curr_static_id->operand[nop].is_operator
- && curr_static_id->operand[nop].type != OP_OUT)
- {
- for (int i = 0; (in = ins[i]) >= 0; i++)
- if (in == nop)
- break;
- if (in < 0
- && regno_val_use_in (regno, *curr_id->operand_loc[nop]) != NULL_RTX)
- return false;
- }
- return true;
-}
-
-/* Generate reloads for matching OUT and INS (array of input operand
- numbers with end marker -1) with reg class GOAL_CLASS, considering
- output operands OUTS (similar array to INS) needing to be in different
- registers. Add input and output reloads correspondingly to the lists
- *BEFORE and *AFTER. OUT might be negative. In this case we generate
- input reloads for matched input operands INS. EARLY_CLOBBER_P is a flag
- that the output operand is early clobbered for chosen alternative. */
-static void
-match_reload (signed char out, signed char *ins, signed char *outs,
- enum reg_class goal_class, rtx_insn **before,
- rtx_insn **after, bool early_clobber_p)
-{
- bool out_conflict;
- int i, in;
- rtx new_in_reg, new_out_reg, reg;
- machine_mode inmode, outmode;
- rtx in_rtx = *curr_id->operand_loc[ins[0]];
- rtx out_rtx = out < 0 ? in_rtx : *curr_id->operand_loc[out];
-
- inmode = curr_operand_mode[ins[0]];
- outmode = out < 0 ? inmode : curr_operand_mode[out];
- push_to_sequence (*before);
- if (inmode != outmode)
- {
- /* process_alt_operands has already checked that the mode sizes
- are ordered. */
- if (partial_subreg_p (outmode, inmode))
- {
- reg = new_in_reg
- = lra_create_new_reg_with_unique_value (inmode, in_rtx,
- goal_class, "");
- new_out_reg = gen_lowpart_SUBREG (outmode, reg);
- LRA_SUBREG_P (new_out_reg) = 1;
- /* If the input reg is dying here, we can use the same hard
- register for REG and IN_RTX. We do it only for original
- pseudos as reload pseudos can die although original
- pseudos still live where reload pseudos dies. */
- if (REG_P (in_rtx) && (int) REGNO (in_rtx) < lra_new_regno_start
- && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))
- && (!early_clobber_p
- || check_conflict_input_operands(REGNO (in_rtx), ins)))
- lra_assign_reg_val (REGNO (in_rtx), REGNO (reg));
- }
- else
- {
- reg = new_out_reg
- = lra_create_new_reg_with_unique_value (outmode, out_rtx,
- goal_class, "");
- new_in_reg = gen_lowpart_SUBREG (inmode, reg);
- /* NEW_IN_REG is non-paradoxical subreg. We don't want
- NEW_OUT_REG living above. We add clobber clause for
- this. This is just a temporary clobber. We can remove
- it at the end of LRA work. */
- rtx_insn *clobber = emit_clobber (new_out_reg);
- LRA_TEMP_CLOBBER_P (PATTERN (clobber)) = 1;
- LRA_SUBREG_P (new_in_reg) = 1;
- if (GET_CODE (in_rtx) == SUBREG)
- {
- rtx subreg_reg = SUBREG_REG (in_rtx);
-
- /* If SUBREG_REG is dying here and sub-registers IN_RTX
- and NEW_IN_REG are similar, we can use the same hard
- register for REG and SUBREG_REG. */
- if (REG_P (subreg_reg)
- && (int) REGNO (subreg_reg) < lra_new_regno_start
- && GET_MODE (subreg_reg) == outmode
- && known_eq (SUBREG_BYTE (in_rtx), SUBREG_BYTE (new_in_reg))
- && find_regno_note (curr_insn, REG_DEAD, REGNO (subreg_reg))
- && (! early_clobber_p
- || check_conflict_input_operands (REGNO (subreg_reg),
- ins)))
- lra_assign_reg_val (REGNO (subreg_reg), REGNO (reg));
- }
- }
- }
- else
- {
- /* Pseudos have values -- see comments for lra_reg_info.
- Different pseudos with the same value do not conflict even if
- they live in the same place. When we create a pseudo we
- assign value of original pseudo (if any) from which we
- created the new pseudo. If we create the pseudo from the
- input pseudo, the new pseudo will have no conflict with the
- input pseudo which is wrong when the input pseudo lives after
- the insn and as the new pseudo value is changed by the insn
- output. Therefore we create the new pseudo from the output
- except the case when we have single matched dying input
- pseudo.
-
- We cannot reuse the current output register because we might
- have a situation like "a <- a op b", where the constraints
- force the second input operand ("b") to match the output
- operand ("a"). "b" must then be copied into a new register
- so that it doesn't clobber the current value of "a".
-
- We cannot use the same value if the output pseudo is
- early clobbered or the input pseudo is mentioned in the
- output, e.g. as an address part in memory, because
- output reload will actually extend the pseudo liveness.
- We don't care about eliminable hard regs here as we are
- interesting only in pseudos. */
-
- /* Matching input's register value is the same as one of the other
- output operand. Output operands in a parallel insn must be in
- different registers. */
- out_conflict = false;
- if (REG_P (in_rtx))
- {
- for (i = 0; outs[i] >= 0; i++)
- {
- rtx other_out_rtx = *curr_id->operand_loc[outs[i]];
- if (outs[i] != out && REG_P (other_out_rtx)
- && (regno_val_use_in (REGNO (in_rtx), other_out_rtx)
- != NULL_RTX))
- {
- out_conflict = true;
- break;
- }
- }
- }
-
- new_in_reg = new_out_reg
- = (! early_clobber_p && ins[1] < 0 && REG_P (in_rtx)
- && (int) REGNO (in_rtx) < lra_new_regno_start
- && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))
- && (! early_clobber_p
- || check_conflict_input_operands (REGNO (in_rtx), ins))
- && (out < 0
- || regno_val_use_in (REGNO (in_rtx), out_rtx) == NULL_RTX)
- && !out_conflict
- ? lra_create_new_reg (inmode, in_rtx, goal_class, "")
- : lra_create_new_reg_with_unique_value (outmode, out_rtx,
- goal_class, ""));
- }
- /* In operand can be got from transformations before processing insn
- constraints. One example of such transformations is subreg
- reloading (see function simplify_operand_subreg). The new
- pseudos created by the transformations might have inaccurate
- class (ALL_REGS) and we should make their classes more
- accurate. */
- narrow_reload_pseudo_class (in_rtx, goal_class);
- lra_emit_move (copy_rtx (new_in_reg), in_rtx);
- *before = get_insns ();
- end_sequence ();
- /* Add the new pseudo to consider values of subsequent input reload
- pseudos. */
- lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS);
- curr_insn_input_reloads[curr_insn_input_reloads_num].input = in_rtx;
- curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = true;
- curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = new_in_reg;
- for (i = 0; (in = ins[i]) >= 0; i++)
- if (GET_MODE (*curr_id->operand_loc[in]) == VOIDmode
- || GET_MODE (new_in_reg) == GET_MODE (*curr_id->operand_loc[in]))
- *curr_id->operand_loc[in] = new_in_reg;
- else
- {
- lra_assert
- (GET_MODE (new_out_reg) == GET_MODE (*curr_id->operand_loc[in]));
- *curr_id->operand_loc[in] = new_out_reg;
- }
- lra_update_dups (curr_id, ins);
- if (out < 0)
- return;
- /* See a comment for the input operand above. */
- narrow_reload_pseudo_class (out_rtx, goal_class);
- if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX)
- {
- reg = SUBREG_P (out_rtx) ? SUBREG_REG (out_rtx) : out_rtx;
- start_sequence ();
- /* If we had strict_low_part, use it also in reload to keep other
- parts unchanged but do it only for regs as strict_low_part
- has no sense for memory and probably there is no insn pattern
- to match the reload insn in memory case. */
- if (out >= 0 && curr_static_id->operand[out].strict_low && REG_P (reg))
- out_rtx = gen_rtx_STRICT_LOW_PART (VOIDmode, out_rtx);
- lra_emit_move (out_rtx, copy_rtx (new_out_reg));
- emit_insn (*after);
- *after = get_insns ();
- end_sequence ();
- }
- *curr_id->operand_loc[out] = new_out_reg;
- lra_update_dup (curr_id, out);
-}
-
-/* Return register class which is union of all reg classes in insn
- constraint alternative string starting with P. */
-static enum reg_class
-reg_class_from_constraints (const char *p)
-{
- int c, len;
- enum reg_class op_class = NO_REGS;
-
- do
- switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
- {
- case '#':
- case ',':
- return op_class;
-
- case 'g':
- op_class = reg_class_subunion[op_class][GENERAL_REGS];
- break;
-
- default:
- enum constraint_num cn = lookup_constraint (p);
- enum reg_class cl = reg_class_for_constraint (cn);
- if (cl == NO_REGS)
- {
- if (insn_extra_address_constraint (cn))
- op_class
- = (reg_class_subunion
- [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
- ADDRESS, SCRATCH)]);
- break;
- }
-
- op_class = reg_class_subunion[op_class][cl];
- break;
- }
- while ((p += len), c);
- return op_class;
-}
-
-/* If OP is a register, return the class of the register as per
- get_reg_class, otherwise return NO_REGS. */
-static inline enum reg_class
-get_op_class (rtx op)
-{
- return REG_P (op) ? get_reg_class (REGNO (op)) : NO_REGS;
-}
-
-/* Return generated insn mem_pseudo:=val if TO_P or val:=mem_pseudo
- otherwise. If modes of MEM_PSEUDO and VAL are different, use
- SUBREG for VAL to make them equal. */
-static rtx_insn *
-emit_spill_move (bool to_p, rtx mem_pseudo, rtx val)
-{
- if (GET_MODE (mem_pseudo) != GET_MODE (val))
- {
- /* Usually size of mem_pseudo is greater than val size but in
- rare cases it can be less as it can be defined by target
- dependent macro HARD_REGNO_CALLER_SAVE_MODE. */
- if (! MEM_P (val))
- {
- val = gen_lowpart_SUBREG (GET_MODE (mem_pseudo),
- GET_CODE (val) == SUBREG
- ? SUBREG_REG (val) : val);
- LRA_SUBREG_P (val) = 1;
- }
- else
- {
- mem_pseudo = gen_lowpart_SUBREG (GET_MODE (val), mem_pseudo);
- LRA_SUBREG_P (mem_pseudo) = 1;
- }
- }
- return to_p ? gen_move_insn (mem_pseudo, val)
- : gen_move_insn (val, mem_pseudo);
-}
-
-/* Process a special case insn (register move), return true if we
- don't need to process it anymore. INSN should be a single set
- insn. Set up that RTL was changed through CHANGE_P and that hook
- TARGET_SECONDARY_MEMORY_NEEDED says to use secondary memory through
- SEC_MEM_P. */
-static bool
-check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
-{
- int sregno, dregno;
- rtx dest, src, dreg, sreg, new_reg, scratch_reg;
- rtx_insn *before;
- enum reg_class dclass, sclass, secondary_class;
- secondary_reload_info sri;
-
- lra_assert (curr_insn_set != NULL_RTX);
- dreg = dest = SET_DEST (curr_insn_set);
- sreg = src = SET_SRC (curr_insn_set);
- if (GET_CODE (dest) == SUBREG)
- dreg = SUBREG_REG (dest);
- if (GET_CODE (src) == SUBREG)
- sreg = SUBREG_REG (src);
- if (! (REG_P (dreg) || MEM_P (dreg)) || ! (REG_P (sreg) || MEM_P (sreg)))
- return false;
- sclass = dclass = NO_REGS;
- if (REG_P (dreg))
- dclass = get_reg_class (REGNO (dreg));
- gcc_assert (dclass < LIM_REG_CLASSES && dclass >= NO_REGS);
- if (dclass == ALL_REGS)
- /* ALL_REGS is used for new pseudos created by transformations
- like reload of SUBREG_REG (see function
- simplify_operand_subreg). We don't know their class yet. We
- should figure out the class from processing the insn
- constraints not in this fast path function. Even if ALL_REGS
- were a right class for the pseudo, secondary_... hooks usually
- are not define for ALL_REGS. */
- return false;
- if (REG_P (sreg))
- sclass = get_reg_class (REGNO (sreg));
- gcc_assert (sclass < LIM_REG_CLASSES && sclass >= NO_REGS);
- if (sclass == ALL_REGS)
- /* See comments above. */
- return false;
- if (sclass == NO_REGS && dclass == NO_REGS)
- return false;
- if (targetm.secondary_memory_needed (GET_MODE (src), sclass, dclass)
- && ((sclass != NO_REGS && dclass != NO_REGS)
- || (GET_MODE (src)
- != targetm.secondary_memory_needed_mode (GET_MODE (src)))))
- {
- *sec_mem_p = true;
- return false;
- }
- if (! REG_P (dreg) || ! REG_P (sreg))
- return false;
- sri.prev_sri = NULL;
- sri.icode = CODE_FOR_nothing;
- sri.extra_cost = 0;
- secondary_class = NO_REGS;
- /* Set up hard register for a reload pseudo for hook
- secondary_reload because some targets just ignore unassigned
- pseudos in the hook. */
- if (dclass != NO_REGS && lra_get_regno_hard_regno (REGNO (dreg)) < 0)
- {
- dregno = REGNO (dreg);
- reg_renumber[dregno] = ira_class_hard_regs[dclass][0];
- }
- else
- dregno = -1;
- if (sclass != NO_REGS && lra_get_regno_hard_regno (REGNO (sreg)) < 0)
- {
- sregno = REGNO (sreg);
- reg_renumber[sregno] = ira_class_hard_regs[sclass][0];
- }
- else
- sregno = -1;
- if (sclass != NO_REGS)
- secondary_class
- = (enum reg_class) targetm.secondary_reload (false, dest,
- (reg_class_t) sclass,
- GET_MODE (src), &sri);
- if (sclass == NO_REGS
- || ((secondary_class != NO_REGS || sri.icode != CODE_FOR_nothing)
- && dclass != NO_REGS))
- {
- enum reg_class old_sclass = secondary_class;
- secondary_reload_info old_sri = sri;
-
- sri.prev_sri = NULL;
- sri.icode = CODE_FOR_nothing;
- sri.extra_cost = 0;
- secondary_class
- = (enum reg_class) targetm.secondary_reload (true, src,
- (reg_class_t) dclass,
- GET_MODE (src), &sri);
- /* Check the target hook consistency. */
- lra_assert
- ((secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing)
- || (old_sclass == NO_REGS && old_sri.icode == CODE_FOR_nothing)
- || (secondary_class == old_sclass && sri.icode == old_sri.icode));
- }
- if (sregno >= 0)
- reg_renumber [sregno] = -1;
- if (dregno >= 0)
- reg_renumber [dregno] = -1;
- if (secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing)
- return false;
- *change_p = true;
- new_reg = NULL_RTX;
- if (secondary_class != NO_REGS)
- new_reg = lra_create_new_reg_with_unique_value (GET_MODE (src), NULL_RTX,
- secondary_class,
- "secondary");
- start_sequence ();
- if (sri.icode == CODE_FOR_nothing)
- lra_emit_move (new_reg, src);
- else
- {
- enum reg_class scratch_class;
-
- scratch_class = (reg_class_from_constraints
- (insn_data[sri.icode].operand[2].constraint));
- scratch_reg = (lra_create_new_reg_with_unique_value
- (insn_data[sri.icode].operand[2].mode, NULL_RTX,
- scratch_class, "scratch"));
- emit_insn (GEN_FCN (sri.icode) (new_reg != NULL_RTX ? new_reg : dest,
- src, scratch_reg));
- }
- before = get_insns ();
- end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL, "Inserting the move");
- if (new_reg != NULL_RTX)
- SET_SRC (curr_insn_set) = new_reg;
- else
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, "Deleting move %u\n", INSN_UID (curr_insn));
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- lra_set_insn_deleted (curr_insn);
- return true;
- }
- return false;
-}
-
-/* The following data describe the result of process_alt_operands.
- The data are used in curr_insn_transform to generate reloads. */
-
-/* The chosen reg classes which should be used for the corresponding
- operands. */
-static enum reg_class goal_alt[MAX_RECOG_OPERANDS];
-/* True if the operand should be the same as another operand and that
- other operand does not need a reload. */
-static bool goal_alt_match_win[MAX_RECOG_OPERANDS];
-/* True if the operand does not need a reload. */
-static bool goal_alt_win[MAX_RECOG_OPERANDS];
-/* True if the operand can be offsetable memory. */
-static bool goal_alt_offmemok[MAX_RECOG_OPERANDS];
-/* The number of an operand to which given operand can be matched to. */
-static int goal_alt_matches[MAX_RECOG_OPERANDS];
-/* The number of elements in the following array. */
-static int goal_alt_dont_inherit_ops_num;
-/* Numbers of operands whose reload pseudos should not be inherited. */
-static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
-/* True if the insn commutative operands should be swapped. */
-static bool goal_alt_swapped;
-/* The chosen insn alternative. */
-static int goal_alt_number;
-
-/* True if the corresponding operand is the result of an equivalence
- substitution. */
-static bool equiv_substition_p[MAX_RECOG_OPERANDS];
-
-/* The following five variables are used to choose the best insn
- alternative. They reflect final characteristics of the best
- alternative. */
-
-/* Number of necessary reloads and overall cost reflecting the
- previous value and other unpleasantness of the best alternative. */
-static int best_losers, best_overall;
-/* Overall number hard registers used for reloads. For example, on
- some targets we need 2 general registers to reload DFmode and only
- one floating point register. */
-static int best_reload_nregs;
-/* Overall number reflecting distances of previous reloading the same
- value. The distances are counted from the current BB start. It is
- used to improve inheritance chances. */
-static int best_reload_sum;
-
-/* True if the current insn should have no correspondingly input or
- output reloads. */
-static bool no_input_reloads_p, no_output_reloads_p;
-
-/* True if we swapped the commutative operands in the current
- insn. */
-static int curr_swapped;
-
-/* if CHECK_ONLY_P is false, arrange for address element *LOC to be a
- register of class CL. Add any input reloads to list BEFORE. AFTER
- is nonnull if *LOC is an automodified value; handle that case by
- adding the required output reloads to list AFTER. Return true if
- the RTL was changed.
-
- if CHECK_ONLY_P is true, check that the *LOC is a correct address
- register. Return false if the address register is correct. */
-static bool
-process_addr_reg (rtx *loc, bool check_only_p, rtx_insn **before, rtx_insn **after,
- enum reg_class cl)
-{
- int regno;
- enum reg_class rclass, new_class;
- rtx reg;
- rtx new_reg;
- machine_mode mode;
- bool subreg_p, before_p = false;
-
- subreg_p = GET_CODE (*loc) == SUBREG;
- if (subreg_p)
- {
- reg = SUBREG_REG (*loc);
- mode = GET_MODE (reg);
-
- /* For mode with size bigger than ptr_mode, there unlikely to be "mov"
- between two registers with different classes, but there normally will
- be "mov" which transfers element of vector register into the general
- register, and this normally will be a subreg which should be reloaded
- as a whole. This is particularly likely to be triggered when
- -fno-split-wide-types specified. */
- if (!REG_P (reg)
- || in_class_p (reg, cl, &new_class)
- || known_le (GET_MODE_SIZE (mode), GET_MODE_SIZE (ptr_mode)))
- loc = &SUBREG_REG (*loc);
- }
-
- reg = *loc;
- mode = GET_MODE (reg);
- if (! REG_P (reg))
- {
- if (check_only_p)
- return true;
- /* Always reload memory in an address even if the target supports
- such addresses. */
- new_reg = lra_create_new_reg_with_unique_value (mode, reg, cl, "address");
- before_p = true;
- }
- else
- {
- regno = REGNO (reg);
- rclass = get_reg_class (regno);
- if (! check_only_p
- && (*loc = get_equiv_with_elimination (reg, curr_insn)) != reg)
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- "Changing pseudo %d in address of insn %u on equiv ",
- REGNO (reg), INSN_UID (curr_insn));
- dump_value_slim (lra_dump_file, *loc, 1);
- fprintf (lra_dump_file, "\n");
- }
- *loc = copy_rtx (*loc);
- }
- if (*loc != reg || ! in_class_p (reg, cl, &new_class))
- {
- if (check_only_p)
- return true;
- reg = *loc;
- if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT,
- mode, reg, cl, subreg_p, "address", &new_reg))
- before_p = true;
- }
- else if (new_class != NO_REGS && rclass != new_class)
- {
- if (check_only_p)
- return true;
- lra_change_class (regno, new_class, " Change to", true);
- return false;
- }
- else
- return false;
- }
- if (before_p)
- {
- push_to_sequence (*before);
- lra_emit_move (new_reg, reg);
- *before = get_insns ();
- end_sequence ();
- }
- *loc = new_reg;
- if (after != NULL)
- {
- start_sequence ();
- lra_emit_move (before_p ? copy_rtx (reg) : reg, new_reg);
- emit_insn (*after);
- *after = get_insns ();
- end_sequence ();
- }
- return true;
-}
-
-/* Insert move insn in simplify_operand_subreg. BEFORE returns
- the insn to be inserted before curr insn. AFTER returns the
- the insn to be inserted after curr insn. ORIGREG and NEWREG
- are the original reg and new reg for reload. */
-static void
-insert_move_for_subreg (rtx_insn **before, rtx_insn **after, rtx origreg,
- rtx newreg)
-{
- if (before)
- {
- push_to_sequence (*before);
- lra_emit_move (newreg, origreg);
- *before = get_insns ();
- end_sequence ();
- }
- if (after)
- {
- start_sequence ();
- lra_emit_move (origreg, newreg);
- emit_insn (*after);
- *after = get_insns ();
- end_sequence ();
- }
-}
-
-static int valid_address_p (machine_mode mode, rtx addr, addr_space_t as);
-static bool process_address (int, bool, rtx_insn **, rtx_insn **);
-
-/* Make reloads for subreg in operand NOP with internal subreg mode
- REG_MODE, add new reloads for further processing. Return true if
- any change was done. */
-static bool
-simplify_operand_subreg (int nop, machine_mode reg_mode)
-{
- int hard_regno, inner_hard_regno;
- rtx_insn *before, *after;
- machine_mode mode, innermode;
- rtx reg, new_reg;
- rtx operand = *curr_id->operand_loc[nop];
- enum reg_class regclass;
- enum op_type type;
-
- before = after = NULL;
-
- if (GET_CODE (operand) != SUBREG)
- return false;
-
- mode = GET_MODE (operand);
- reg = SUBREG_REG (operand);
- innermode = GET_MODE (reg);
- type = curr_static_id->operand[nop].type;
- if (MEM_P (reg))
- {
- const bool addr_was_valid
- = valid_address_p (innermode, XEXP (reg, 0), MEM_ADDR_SPACE (reg));
- alter_subreg (curr_id->operand_loc[nop], false);
- rtx subst = *curr_id->operand_loc[nop];
- lra_assert (MEM_P (subst));
- const bool addr_is_valid = valid_address_p (GET_MODE (subst),
- XEXP (subst, 0),
- MEM_ADDR_SPACE (subst));
- if (!addr_was_valid
- || addr_is_valid
- || ((get_constraint_type (lookup_constraint
- (curr_static_id->operand[nop].constraint))
- != CT_SPECIAL_MEMORY)
- /* We still can reload address and if the address is
- valid, we can remove subreg without reloading its
- inner memory. */
- && valid_address_p (GET_MODE (subst),
- regno_reg_rtx
- [ira_class_hard_regs
- [base_reg_class (GET_MODE (subst),
- MEM_ADDR_SPACE (subst),
- ADDRESS, SCRATCH)][0]],
- MEM_ADDR_SPACE (subst))))
- {
- /* If we change the address for a paradoxical subreg of memory, the
- new address might violate the necessary alignment or the access
- might be slow; take this into consideration. We need not worry
- about accesses beyond allocated memory for paradoxical memory
- subregs as we don't substitute such equiv memory (see processing
- equivalences in function lra_constraints) and because for spilled
- pseudos we allocate stack memory enough for the biggest
- corresponding paradoxical subreg.
-
- However, do not blindly simplify a (subreg (mem ...)) for
- WORD_REGISTER_OPERATIONS targets as this may lead to loading junk
- data into a register when the inner is narrower than outer or
- missing important data from memory when the inner is wider than
- outer. This rule only applies to modes that are no wider than
- a word.
-
- If valid memory becomes invalid after subreg elimination
- and address might be different we still have to reload
- memory.
- */
- if ((! addr_was_valid
- || addr_is_valid
- || known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (innermode)))
- && !(maybe_ne (GET_MODE_PRECISION (mode),
- GET_MODE_PRECISION (innermode))
- && known_le (GET_MODE_SIZE (mode), UNITS_PER_WORD)
- && known_le (GET_MODE_SIZE (innermode), UNITS_PER_WORD)
- && WORD_REGISTER_OPERATIONS)
- && (!(MEM_ALIGN (subst) < GET_MODE_ALIGNMENT (mode)
- && targetm.slow_unaligned_access (mode, MEM_ALIGN (subst)))
- || (MEM_ALIGN (reg) < GET_MODE_ALIGNMENT (innermode)
- && targetm.slow_unaligned_access (innermode,
- MEM_ALIGN (reg)))))
- return true;
-
- *curr_id->operand_loc[nop] = operand;
-
- /* But if the address was not valid, we cannot reload the MEM without
- reloading the address first. */
- if (!addr_was_valid)
- process_address (nop, false, &before, &after);
-
- /* INNERMODE is fast, MODE slow. Reload the mem in INNERMODE. */
- enum reg_class rclass
- = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
- if (get_reload_reg (curr_static_id->operand[nop].type, innermode,
- reg, rclass, TRUE, "slow/invalid mem", &new_reg))
- {
- bool insert_before, insert_after;
- bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
-
- insert_before = (type != OP_OUT
- || partial_subreg_p (mode, innermode));
- insert_after = type != OP_IN;
- insert_move_for_subreg (insert_before ? &before : NULL,
- insert_after ? &after : NULL,
- reg, new_reg);
- }
- SUBREG_REG (operand) = new_reg;
-
- /* Convert to MODE. */
- reg = operand;
- rclass
- = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
- if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg,
- rclass, TRUE, "slow/invalid mem", &new_reg))
- {
- bool insert_before, insert_after;
- bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
-
- insert_before = type != OP_OUT;
- insert_after = type != OP_IN;
- insert_move_for_subreg (insert_before ? &before : NULL,
- insert_after ? &after : NULL,
- reg, new_reg);
- }
- *curr_id->operand_loc[nop] = new_reg;
- lra_process_new_insns (curr_insn, before, after,
- "Inserting slow/invalid mem reload");
- return true;
- }
-
- /* If the address was valid and became invalid, prefer to reload
- the memory. Typical case is when the index scale should
- correspond the memory. */
- *curr_id->operand_loc[nop] = operand;
- /* Do not return false here as the MEM_P (reg) will be processed
- later in this function. */
- }
- else if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
- {
- alter_subreg (curr_id->operand_loc[nop], false);
- return true;
- }
- else if (CONSTANT_P (reg))
- {
- /* Try to simplify subreg of constant. It is usually result of
- equivalence substitution. */
- if (innermode == VOIDmode
- && (innermode = original_subreg_reg_mode[nop]) == VOIDmode)
- innermode = curr_static_id->operand[nop].mode;
- if ((new_reg = simplify_subreg (mode, reg, innermode,
- SUBREG_BYTE (operand))) != NULL_RTX)
- {
- *curr_id->operand_loc[nop] = new_reg;
- return true;
- }
- }
- /* Put constant into memory when we have mixed modes. It generates
- a better code in most cases as it does not need a secondary
- reload memory. It also prevents LRA looping when LRA is using
- secondary reload memory again and again. */
- if (CONSTANT_P (reg) && CONST_POOL_OK_P (reg_mode, reg)
- && SCALAR_INT_MODE_P (reg_mode) != SCALAR_INT_MODE_P (mode))
- {
- SUBREG_REG (operand) = force_const_mem (reg_mode, reg);
- alter_subreg (curr_id->operand_loc[nop], false);
- return true;
- }
- /* Force a reload of the SUBREG_REG if this is a constant or PLUS or
- if there may be a problem accessing OPERAND in the outer
- mode. */
- if ((REG_P (reg)
- && REGNO (reg) >= FIRST_PSEUDO_REGISTER
- && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0
- /* Don't reload paradoxical subregs because we could be looping
- having repeatedly final regno out of hard regs range. */
- && (hard_regno_nregs (hard_regno, innermode)
- >= hard_regno_nregs (hard_regno, mode))
- && simplify_subreg_regno (hard_regno, innermode,
- SUBREG_BYTE (operand), mode) < 0
- /* Don't reload subreg for matching reload. It is actually
- valid subreg in LRA. */
- && ! LRA_SUBREG_P (operand))
- || CONSTANT_P (reg) || GET_CODE (reg) == PLUS || MEM_P (reg))
- {
- enum reg_class rclass;
-
- if (REG_P (reg))
- /* There is a big probability that we will get the same class
- for the new pseudo and we will get the same insn which
- means infinite looping. So spill the new pseudo. */
- rclass = NO_REGS;
- else
- /* The class will be defined later in curr_insn_transform. */
- rclass
- = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
-
- if (get_reload_reg (curr_static_id->operand[nop].type, reg_mode, reg,
- rclass, TRUE, "subreg reg", &new_reg))
- {
- bool insert_before, insert_after;
- bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
-
- insert_before = (type != OP_OUT
- || read_modify_subreg_p (operand));
- insert_after = (type != OP_IN);
- insert_move_for_subreg (insert_before ? &before : NULL,
- insert_after ? &after : NULL,
- reg, new_reg);
- }
- SUBREG_REG (operand) = new_reg;
- lra_process_new_insns (curr_insn, before, after,
- "Inserting subreg reload");
- return true;
- }
- /* Force a reload for a paradoxical subreg. For paradoxical subreg,
- IRA allocates hardreg to the inner pseudo reg according to its mode
- instead of the outermode, so the size of the hardreg may not be enough
- to contain the outermode operand, in that case we may need to insert
- reload for the reg. For the following two types of paradoxical subreg,
- we need to insert reload:
- 1. If the op_type is OP_IN, and the hardreg could not be paired with
- other hardreg to contain the outermode operand
- (checked by in_hard_reg_set_p), we need to insert the reload.
- 2. If the op_type is OP_OUT or OP_INOUT.
-
- Here is a paradoxical subreg example showing how the reload is generated:
-
- (insn 5 4 7 2 (set (reg:TI 106 [ __comp ])
- (subreg:TI (reg:DI 107 [ __comp ]) 0)) {*movti_internal_rex64}
-
- In IRA, reg107 is allocated to a DImode hardreg. We use x86-64 as example
- here, if reg107 is assigned to hardreg R15, because R15 is the last
- hardreg, compiler cannot find another hardreg to pair with R15 to
- contain TImode data. So we insert a TImode reload reg180 for it.
- After reload is inserted:
-
- (insn 283 0 0 (set (subreg:DI (reg:TI 180 [orig:107 __comp ] [107]) 0)
- (reg:DI 107 [ __comp ])) -1
- (insn 5 4 7 2 (set (reg:TI 106 [ __comp ])
- (subreg:TI (reg:TI 180 [orig:107 __comp ] [107]) 0)) {*movti_internal_rex64}
-
- Two reload hard registers will be allocated to reg180 to save TImode data
- in LRA_assign.
-
- For LRA pseudos this should normally be handled by the biggest_mode
- mechanism. However, it's possible for new uses of an LRA pseudo
- to be introduced after we've allocated it, such as when undoing
- inheritance, and the allocated register might not then be appropriate
- for the new uses. */
- else if (REG_P (reg)
- && REGNO (reg) >= FIRST_PSEUDO_REGISTER
- && paradoxical_subreg_p (operand)
- && (inner_hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0
- && ((hard_regno
- = simplify_subreg_regno (inner_hard_regno, innermode,
- SUBREG_BYTE (operand), mode)) < 0
- || ((hard_regno_nregs (inner_hard_regno, innermode)
- < hard_regno_nregs (hard_regno, mode))
- && (regclass = lra_get_allocno_class (REGNO (reg)))
- && (type != OP_IN
- || !in_hard_reg_set_p (reg_class_contents[regclass],
- mode, hard_regno)
- || overlaps_hard_reg_set_p (lra_no_alloc_regs,
- mode, hard_regno)))))
- {
- /* The class will be defined later in curr_insn_transform. */
- enum reg_class rclass
- = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
-
- if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg,
- rclass, TRUE, "paradoxical subreg", &new_reg))
- {
- rtx subreg;
- bool insert_before, insert_after;
-
- PUT_MODE (new_reg, mode);
- subreg = gen_lowpart_SUBREG (innermode, new_reg);
- bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
-
- insert_before = (type != OP_OUT);
- insert_after = (type != OP_IN);
- insert_move_for_subreg (insert_before ? &before : NULL,
- insert_after ? &after : NULL,
- reg, subreg);
- }
- SUBREG_REG (operand) = new_reg;
- lra_process_new_insns (curr_insn, before, after,
- "Inserting paradoxical subreg reload");
- return true;
- }
- return false;
-}
-
-/* Return TRUE if X refers for a hard register from SET. */
-static bool
-uses_hard_regs_p (rtx x, HARD_REG_SET set)
-{
- int i, j, x_hard_regno;
- machine_mode mode;
- const char *fmt;
- enum rtx_code code;
-
- if (x == NULL_RTX)
- return false;
- code = GET_CODE (x);
- mode = GET_MODE (x);
-
- if (code == SUBREG)
- {
- /* For all SUBREGs we want to check whether the full multi-register
- overlaps the set. For normal SUBREGs this means 'get_hard_regno' of
- the inner register, for paradoxical SUBREGs this means the
- 'get_hard_regno' of the full SUBREG and for complete SUBREGs either is
- fine. Use the wider mode for all cases. */
- rtx subreg = SUBREG_REG (x);
- mode = wider_subreg_mode (x);
- if (mode == GET_MODE (subreg))
- {
- x = subreg;
- code = GET_CODE (x);
- }
- }
-
- if (REG_P (x) || SUBREG_P (x))
- {
- x_hard_regno = get_hard_regno (x, true);
- return (x_hard_regno >= 0
- && overlaps_hard_reg_set_p (set, mode, x_hard_regno));
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (uses_hard_regs_p (XEXP (x, i), set))
- return true;
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (uses_hard_regs_p (XVECEXP (x, i, j), set))
- return true;
- }
- }
- return false;
-}
-
-/* Return true if OP is a spilled pseudo. */
-static inline bool
-spilled_pseudo_p (rtx op)
-{
- return (REG_P (op)
- && REGNO (op) >= FIRST_PSEUDO_REGISTER && in_mem_p (REGNO (op)));
-}
-
-/* Return true if X is a general constant. */
-static inline bool
-general_constant_p (rtx x)
-{
- return CONSTANT_P (x) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (x));
-}
-
-static bool
-reg_in_class_p (rtx reg, enum reg_class cl)
-{
- if (cl == NO_REGS)
- return get_reg_class (REGNO (reg)) == NO_REGS;
- return in_class_p (reg, cl, NULL);
-}
-
-/* Return true if SET of RCLASS contains no hard regs which can be
- used in MODE. */
-static bool
-prohibited_class_reg_set_mode_p (enum reg_class rclass,
- HARD_REG_SET &set,
- machine_mode mode)
-{
- HARD_REG_SET temp;
-
- lra_assert (hard_reg_set_subset_p (reg_class_contents[rclass], set));
- temp = set & ~lra_no_alloc_regs;
- return (hard_reg_set_subset_p
- (temp, ira_prohibited_class_mode_regs[rclass][mode]));
-}
-
-
-/* Used to check validity info about small class input operands. It
- should be incremented at start of processing an insn
- alternative. */
-static unsigned int curr_small_class_check = 0;
-
-/* Update number of used inputs of class OP_CLASS for operand NOP
- of alternative NALT. Return true if we have more such class operands
- than the number of available regs. */
-static bool
-update_and_check_small_class_inputs (int nop, int nalt,
- enum reg_class op_class)
-{
- static unsigned int small_class_check[LIM_REG_CLASSES];
- static int small_class_input_nums[LIM_REG_CLASSES];
-
- if (SMALL_REGISTER_CLASS_P (op_class)
- /* We are interesting in classes became small because of fixing
- some hard regs, e.g. by an user through GCC options. */
- && hard_reg_set_intersect_p (reg_class_contents[op_class],
- ira_no_alloc_regs)
- && (curr_static_id->operand[nop].type != OP_OUT
- || TEST_BIT (curr_static_id->operand[nop].early_clobber_alts, nalt)))
- {
- if (small_class_check[op_class] == curr_small_class_check)
- small_class_input_nums[op_class]++;
- else
- {
- small_class_check[op_class] = curr_small_class_check;
- small_class_input_nums[op_class] = 1;
- }
- if (small_class_input_nums[op_class] > ira_class_hard_regs_num[op_class])
- return true;
- }
- return false;
-}
-
-/* Major function to choose the current insn alternative and what
- operands should be reloaded and how. If ONLY_ALTERNATIVE is not
- negative we should consider only this alternative. Return false if
- we cannot choose the alternative or find how to reload the
- operands. */
-static bool
-process_alt_operands (int only_alternative)
-{
- bool ok_p = false;
- int nop, overall, nalt;
- int n_alternatives = curr_static_id->n_alternatives;
- int n_operands = curr_static_id->n_operands;
- /* LOSERS counts the operands that don't fit this alternative and
- would require loading. */
- int losers;
- int addr_losers;
- /* REJECT is a count of how undesirable this alternative says it is
- if any reloading is required. If the alternative matches exactly
- then REJECT is ignored, but otherwise it gets this much counted
- against it in addition to the reloading needed. */
- int reject;
- /* This is defined by '!' or '?' alternative constraint and added to
- reject. But in some cases it can be ignored. */
- int static_reject;
- int op_reject;
- /* The number of elements in the following array. */
- int early_clobbered_regs_num;
- /* Numbers of operands which are early clobber registers. */
- int early_clobbered_nops[MAX_RECOG_OPERANDS];
- enum reg_class curr_alt[MAX_RECOG_OPERANDS];
- HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS];
- bool curr_alt_match_win[MAX_RECOG_OPERANDS];
- bool curr_alt_win[MAX_RECOG_OPERANDS];
- bool curr_alt_offmemok[MAX_RECOG_OPERANDS];
- int curr_alt_matches[MAX_RECOG_OPERANDS];
- /* The number of elements in the following array. */
- int curr_alt_dont_inherit_ops_num;
- /* Numbers of operands whose reload pseudos should not be inherited. */
- int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
- rtx op;
- /* The register when the operand is a subreg of register, otherwise the
- operand itself. */
- rtx no_subreg_reg_operand[MAX_RECOG_OPERANDS];
- /* The register if the operand is a register or subreg of register,
- otherwise NULL. */
- rtx operand_reg[MAX_RECOG_OPERANDS];
- int hard_regno[MAX_RECOG_OPERANDS];
- machine_mode biggest_mode[MAX_RECOG_OPERANDS];
- int reload_nregs, reload_sum;
- bool costly_p;
- enum reg_class cl;
-
- /* Calculate some data common for all alternatives to speed up the
- function. */
- for (nop = 0; nop < n_operands; nop++)
- {
- rtx reg;
-
- op = no_subreg_reg_operand[nop] = *curr_id->operand_loc[nop];
- /* The real hard regno of the operand after the allocation. */
- hard_regno[nop] = get_hard_regno (op, true);
-
- operand_reg[nop] = reg = op;
- biggest_mode[nop] = GET_MODE (op);
- if (GET_CODE (op) == SUBREG)
- {
- biggest_mode[nop] = wider_subreg_mode (op);
- operand_reg[nop] = reg = SUBREG_REG (op);
- }
- if (! REG_P (reg))
- operand_reg[nop] = NULL_RTX;
- else if (REGNO (reg) >= FIRST_PSEUDO_REGISTER
- || ((int) REGNO (reg)
- == lra_get_elimination_hard_regno (REGNO (reg))))
- no_subreg_reg_operand[nop] = reg;
- else
- operand_reg[nop] = no_subreg_reg_operand[nop]
- /* Just use natural mode for elimination result. It should
- be enough for extra constraints hooks. */
- = regno_reg_rtx[hard_regno[nop]];
- }
-
- /* The constraints are made of several alternatives. Each operand's
- constraint looks like foo,bar,... with commas separating the
- alternatives. The first alternatives for all operands go
- together, the second alternatives go together, etc.
-
- First loop over alternatives. */
- alternative_mask preferred = curr_id->preferred_alternatives;
- if (only_alternative >= 0)
- preferred &= ALTERNATIVE_BIT (only_alternative);
-
- for (nalt = 0; nalt < n_alternatives; nalt++)
- {
- /* Loop over operands for one constraint alternative. */
- if (!TEST_BIT (preferred, nalt))
- continue;
-
- bool matching_early_clobber[MAX_RECOG_OPERANDS];
- curr_small_class_check++;
- overall = losers = addr_losers = 0;
- static_reject = reject = reload_nregs = reload_sum = 0;
- for (nop = 0; nop < n_operands; nop++)
- {
- int inc = (curr_static_id
- ->operand_alternative[nalt * n_operands + nop].reject);
- if (lra_dump_file != NULL && inc != 0)
- fprintf (lra_dump_file,
- " Staticly defined alt reject+=%d\n", inc);
- static_reject += inc;
- matching_early_clobber[nop] = 0;
- }
- reject += static_reject;
- early_clobbered_regs_num = 0;
-
- for (nop = 0; nop < n_operands; nop++)
- {
- const char *p;
- char *end;
- int len, c, m, i, opalt_num, this_alternative_matches;
- bool win, did_match, offmemok, early_clobber_p;
- /* false => this operand can be reloaded somehow for this
- alternative. */
- bool badop;
- /* true => this operand can be reloaded if the alternative
- allows regs. */
- bool winreg;
- /* True if a constant forced into memory would be OK for
- this operand. */
- bool constmemok;
- enum reg_class this_alternative, this_costly_alternative;
- HARD_REG_SET this_alternative_set, this_costly_alternative_set;
- bool this_alternative_match_win, this_alternative_win;
- bool this_alternative_offmemok;
- bool scratch_p;
- machine_mode mode;
- enum constraint_num cn;
-
- opalt_num = nalt * n_operands + nop;
- if (curr_static_id->operand_alternative[opalt_num].anything_ok)
- {
- /* Fast track for no constraints at all. */
- curr_alt[nop] = NO_REGS;
- CLEAR_HARD_REG_SET (curr_alt_set[nop]);
- curr_alt_win[nop] = true;
- curr_alt_match_win[nop] = false;
- curr_alt_offmemok[nop] = false;
- curr_alt_matches[nop] = -1;
- continue;
- }
-
- op = no_subreg_reg_operand[nop];
- mode = curr_operand_mode[nop];
-
- win = did_match = winreg = offmemok = constmemok = false;
- badop = true;
-
- early_clobber_p = false;
- p = curr_static_id->operand_alternative[opalt_num].constraint;
-
- this_costly_alternative = this_alternative = NO_REGS;
- /* We update set of possible hard regs besides its class
- because reg class might be inaccurate. For example,
- union of LO_REGS (l), HI_REGS(h), and STACK_REG(k) in ARM
- is translated in HI_REGS because classes are merged by
- pairs and there is no accurate intermediate class. */
- CLEAR_HARD_REG_SET (this_alternative_set);
- CLEAR_HARD_REG_SET (this_costly_alternative_set);
- this_alternative_win = false;
- this_alternative_match_win = false;
- this_alternative_offmemok = false;
- this_alternative_matches = -1;
-
- /* An empty constraint should be excluded by the fast
- track. */
- lra_assert (*p != 0 && *p != ',');
-
- op_reject = 0;
- /* Scan this alternative's specs for this operand; set WIN
- if the operand fits any letter in this alternative.
- Otherwise, clear BADOP if this operand could fit some
- letter after reloads, or set WINREG if this operand could
- fit after reloads provided the constraint allows some
- registers. */
- costly_p = false;
- do
- {
- switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
- {
- case '\0':
- len = 0;
- break;
- case ',':
- c = '\0';
- break;
-
- case '&':
- early_clobber_p = true;
- break;
-
- case '$':
- op_reject += LRA_MAX_REJECT;
- break;
- case '^':
- op_reject += LRA_LOSER_COST_FACTOR;
- break;
-
- case '#':
- /* Ignore rest of this alternative. */
- c = '\0';
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- int m_hregno;
- bool match_p;
-
- m = strtoul (p, &end, 10);
- p = end;
- len = 0;
- lra_assert (nop > m);
-
- /* Reject matches if we don't know which operand is
- bigger. This situation would arguably be a bug in
- an .md pattern, but could also occur in a user asm. */
- if (!ordered_p (GET_MODE_SIZE (biggest_mode[m]),
- GET_MODE_SIZE (biggest_mode[nop])))
- break;
-
- /* Don't match wrong asm insn operands for proper
- diagnostic later. */
- if (INSN_CODE (curr_insn) < 0
- && (curr_operand_mode[m] == BLKmode
- || curr_operand_mode[nop] == BLKmode)
- && curr_operand_mode[m] != curr_operand_mode[nop])
- break;
-
- m_hregno = get_hard_regno (*curr_id->operand_loc[m], false);
- /* We are supposed to match a previous operand.
- If we do, we win if that one did. If we do
- not, count both of the operands as losers.
- (This is too conservative, since most of the
- time only a single reload insn will be needed
- to make the two operands win. As a result,
- this alternative may be rejected when it is
- actually desirable.) */
- match_p = false;
- if (operands_match_p (*curr_id->operand_loc[nop],
- *curr_id->operand_loc[m], m_hregno))
- {
- /* We should reject matching of an early
- clobber operand if the matching operand is
- not dying in the insn. */
- if (!TEST_BIT (curr_static_id->operand[m]
- .early_clobber_alts, nalt)
- || operand_reg[nop] == NULL_RTX
- || (find_regno_note (curr_insn, REG_DEAD,
- REGNO (op))
- || REGNO (op) == REGNO (operand_reg[m])))
- match_p = true;
- }
- if (match_p)
- {
- /* If we are matching a non-offsettable
- address where an offsettable address was
- expected, then we must reject this
- combination, because we can't reload
- it. */
- if (curr_alt_offmemok[m]
- && MEM_P (*curr_id->operand_loc[m])
- && curr_alt[m] == NO_REGS && ! curr_alt_win[m])
- continue;
- }
- else
- {
- /* If the operands do not match and one
- operand is INOUT, we can not match them.
- Try other possibilities, e.g. other
- alternatives or commutative operand
- exchange. */
- if (curr_static_id->operand[nop].type == OP_INOUT
- || curr_static_id->operand[m].type == OP_INOUT)
- break;
- /* Operands don't match. If the operands are
- different user defined explicit hard
- registers, then we cannot make them match
- when one is early clobber operand. */
- if ((REG_P (*curr_id->operand_loc[nop])
- || SUBREG_P (*curr_id->operand_loc[nop]))
- && (REG_P (*curr_id->operand_loc[m])
- || SUBREG_P (*curr_id->operand_loc[m])))
- {
- rtx nop_reg = *curr_id->operand_loc[nop];
- if (SUBREG_P (nop_reg))
- nop_reg = SUBREG_REG (nop_reg);
- rtx m_reg = *curr_id->operand_loc[m];
- if (SUBREG_P (m_reg))
- m_reg = SUBREG_REG (m_reg);
-
- if (REG_P (nop_reg)
- && HARD_REGISTER_P (nop_reg)
- && REG_USERVAR_P (nop_reg)
- && REG_P (m_reg)
- && HARD_REGISTER_P (m_reg)
- && REG_USERVAR_P (m_reg))
- {
- int i;
-
- for (i = 0; i < early_clobbered_regs_num; i++)
- if (m == early_clobbered_nops[i])
- break;
- if (i < early_clobbered_regs_num
- || early_clobber_p)
- break;
- }
- }
- /* Both operands must allow a reload register,
- otherwise we cannot make them match. */
- if (curr_alt[m] == NO_REGS)
- break;
- /* Retroactively mark the operand we had to
- match as a loser, if it wasn't already and
- it wasn't matched to a register constraint
- (e.g it might be matched by memory). */
- if (curr_alt_win[m]
- && (operand_reg[m] == NULL_RTX
- || hard_regno[m] < 0))
- {
- losers++;
- reload_nregs
- += (ira_reg_class_max_nregs[curr_alt[m]]
- [GET_MODE (*curr_id->operand_loc[m])]);
- }
-
- /* Prefer matching earlyclobber alternative as
- it results in less hard regs required for
- the insn than a non-matching earlyclobber
- alternative. */
- if (TEST_BIT (curr_static_id->operand[m]
- .early_clobber_alts, nalt))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Matching earlyclobber alt:"
- " reject--\n",
- nop);
- if (!matching_early_clobber[m])
- {
- reject--;
- matching_early_clobber[m] = 1;
- }
- }
- /* Otherwise we prefer no matching
- alternatives because it gives more freedom
- in RA. */
- else if (operand_reg[nop] == NULL_RTX
- || (find_regno_note (curr_insn, REG_DEAD,
- REGNO (operand_reg[nop]))
- == NULL_RTX))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Matching alt: reject+=2\n",
- nop);
- reject += 2;
- }
- }
- /* If we have to reload this operand and some
- previous operand also had to match the same
- thing as this operand, we don't know how to do
- that. */
- if (!match_p || !curr_alt_win[m])
- {
- for (i = 0; i < nop; i++)
- if (curr_alt_matches[i] == m)
- break;
- if (i < nop)
- break;
- }
- else
- did_match = true;
-
- this_alternative_matches = m;
- /* This can be fixed with reloads if the operand
- we are supposed to match can be fixed with
- reloads. */
- badop = false;
- this_alternative = curr_alt[m];
- this_alternative_set = curr_alt_set[m];
- winreg = this_alternative != NO_REGS;
- break;
- }
-
- case 'g':
- if (MEM_P (op)
- || general_constant_p (op)
- || spilled_pseudo_p (op))
- win = true;
- cl = GENERAL_REGS;
- goto reg;
-
- default:
- cn = lookup_constraint (p);
- switch (get_constraint_type (cn))
- {
- case CT_REGISTER:
- cl = reg_class_for_constraint (cn);
- if (cl != NO_REGS)
- goto reg;
- break;
-
- case CT_CONST_INT:
- if (CONST_INT_P (op)
- && insn_const_int_ok_for_constraint (INTVAL (op), cn))
- win = true;
- break;
-
- case CT_MEMORY:
- case CT_RELAXED_MEMORY:
- if (MEM_P (op)
- && satisfies_memory_constraint_p (op, cn))
- win = true;
- else if (spilled_pseudo_p (op))
- win = true;
-
- /* If we didn't already win, we can reload constants
- via force_const_mem or put the pseudo value into
- memory, or make other memory by reloading the
- address like for 'o'. */
- if (CONST_POOL_OK_P (mode, op)
- || MEM_P (op) || REG_P (op)
- /* We can restore the equiv insn by a
- reload. */
- || equiv_substition_p[nop])
- badop = false;
- constmemok = true;
- offmemok = true;
- break;
-
- case CT_ADDRESS:
- /* An asm operand with an address constraint
- that doesn't satisfy address_operand has
- is_address cleared, so that we don't try to
- make a non-address fit. */
- if (!curr_static_id->operand[nop].is_address)
- break;
- /* If we didn't already win, we can reload the address
- into a base register. */
- if (satisfies_address_constraint_p (op, cn))
- win = true;
- cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
- ADDRESS, SCRATCH);
- badop = false;
- goto reg;
-
- case CT_FIXED_FORM:
- if (constraint_satisfied_p (op, cn))
- win = true;
- break;
-
- case CT_SPECIAL_MEMORY:
- if (satisfies_memory_constraint_p (op, cn))
- win = true;
- else if (spilled_pseudo_p (op))
- win = true;
- break;
- }
- break;
-
- reg:
- if (mode == BLKmode)
- break;
- this_alternative = reg_class_subunion[this_alternative][cl];
- this_alternative_set |= reg_class_contents[cl];
- if (costly_p)
- {
- this_costly_alternative
- = reg_class_subunion[this_costly_alternative][cl];
- this_costly_alternative_set |= reg_class_contents[cl];
- }
- winreg = true;
- if (REG_P (op))
- {
- if (hard_regno[nop] >= 0
- && in_hard_reg_set_p (this_alternative_set,
- mode, hard_regno[nop]))
- win = true;
- else if (hard_regno[nop] < 0
- && in_class_p (op, this_alternative, NULL))
- win = true;
- }
- break;
- }
- if (c != ' ' && c != '\t')
- costly_p = c == '*';
- }
- while ((p += len), c);
-
- scratch_p = (operand_reg[nop] != NULL_RTX
- && ira_former_scratch_p (REGNO (operand_reg[nop])));
- /* Record which operands fit this alternative. */
- if (win)
- {
- this_alternative_win = true;
- if (operand_reg[nop] != NULL_RTX)
- {
- if (hard_regno[nop] >= 0)
- {
- if (in_hard_reg_set_p (this_costly_alternative_set,
- mode, hard_regno[nop]))
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " %d Costly set: reject++\n",
- nop);
- reject++;
- }
- }
- else
- {
- /* Prefer won reg to spilled pseudo under other
- equal conditions for possibe inheritance. */
- if (! scratch_p)
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Non pseudo reload: reject++\n",
- nop);
- reject++;
- }
- if (in_class_p (operand_reg[nop],
- this_costly_alternative, NULL))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Non pseudo costly reload:"
- " reject++\n",
- nop);
- reject++;
- }
- }
- /* We simulate the behavior of old reload here.
- Although scratches need hard registers and it
- might result in spilling other pseudos, no reload
- insns are generated for the scratches. So it
- might cost something but probably less than old
- reload pass believes. */
- if (scratch_p)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " %d Scratch win: reject+=2\n",
- nop);
- reject += 2;
- }
- }
- }
- else if (did_match)
- this_alternative_match_win = true;
- else
- {
- int const_to_mem = 0;
- bool no_regs_p;
-
- reject += op_reject;
- /* Never do output reload of stack pointer. It makes
- impossible to do elimination when SP is changed in
- RTL. */
- if (op == stack_pointer_rtx && ! frame_pointer_needed
- && curr_static_id->operand[nop].type != OP_IN)
- goto fail;
-
- /* If this alternative asks for a specific reg class, see if there
- is at least one allocatable register in that class. */
- no_regs_p
- = (this_alternative == NO_REGS
- || (hard_reg_set_subset_p
- (reg_class_contents[this_alternative],
- lra_no_alloc_regs)));
-
- /* For asms, verify that the class for this alternative is possible
- for the mode that is specified. */
- if (!no_regs_p && INSN_CODE (curr_insn) < 0)
- {
- int i;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (targetm.hard_regno_mode_ok (i, mode)
- && in_hard_reg_set_p (reg_class_contents[this_alternative],
- mode, i))
- break;
- if (i == FIRST_PSEUDO_REGISTER)
- winreg = false;
- }
-
- /* If this operand accepts a register, and if the
- register class has at least one allocatable register,
- then this operand can be reloaded. */
- if (winreg && !no_regs_p)
- badop = false;
-
- if (badop)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " alt=%d: Bad operand -- refuse\n",
- nalt);
- goto fail;
- }
-
- if (this_alternative != NO_REGS)
- {
- HARD_REG_SET available_regs
- = (reg_class_contents[this_alternative]
- & ~((ira_prohibited_class_mode_regs
- [this_alternative][mode])
- | lra_no_alloc_regs));
- if (hard_reg_set_empty_p (available_regs))
- {
- /* There are no hard regs holding a value of given
- mode. */
- if (offmemok)
- {
- this_alternative = NO_REGS;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " %d Using memory because of"
- " a bad mode: reject+=2\n",
- nop);
- reject += 2;
- }
- else
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " alt=%d: Wrong mode -- refuse\n",
- nalt);
- goto fail;
- }
- }
- }
-
- /* If not assigned pseudo has a class which a subset of
- required reg class, it is a less costly alternative
- as the pseudo still can get a hard reg of necessary
- class. */
- if (! no_regs_p && REG_P (op) && hard_regno[nop] < 0
- && (cl = get_reg_class (REGNO (op))) != NO_REGS
- && ira_class_subset_p[this_alternative][cl])
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Super set class reg: reject-=3\n", nop);
- reject -= 3;
- }
-
- this_alternative_offmemok = offmemok;
- if (this_costly_alternative != NO_REGS)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " %d Costly loser: reject++\n", nop);
- reject++;
- }
- /* If the operand is dying, has a matching constraint,
- and satisfies constraints of the matched operand
- which failed to satisfy the own constraints, most probably
- the reload for this operand will be gone. */
- if (this_alternative_matches >= 0
- && !curr_alt_win[this_alternative_matches]
- && REG_P (op)
- && find_regno_note (curr_insn, REG_DEAD, REGNO (op))
- && (hard_regno[nop] >= 0
- ? in_hard_reg_set_p (this_alternative_set,
- mode, hard_regno[nop])
- : in_class_p (op, this_alternative, NULL)))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Dying matched operand reload: reject++\n",
- nop);
- reject++;
- }
- else
- {
- /* Strict_low_part requires to reload the register
- not the sub-register. In this case we should
- check that a final reload hard reg can hold the
- value mode. */
- if (curr_static_id->operand[nop].strict_low
- && REG_P (op)
- && hard_regno[nop] < 0
- && GET_CODE (*curr_id->operand_loc[nop]) == SUBREG
- && ira_class_hard_regs_num[this_alternative] > 0
- && (!targetm.hard_regno_mode_ok
- (ira_class_hard_regs[this_alternative][0],
- GET_MODE (*curr_id->operand_loc[nop]))))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " alt=%d: Strict low subreg reload -- refuse\n",
- nalt);
- goto fail;
- }
- losers++;
- }
- if (operand_reg[nop] != NULL_RTX
- /* Output operands and matched input operands are
- not inherited. The following conditions do not
- exactly describe the previous statement but they
- are pretty close. */
- && curr_static_id->operand[nop].type != OP_OUT
- && (this_alternative_matches < 0
- || curr_static_id->operand[nop].type != OP_IN))
- {
- int last_reload = (lra_reg_info[ORIGINAL_REGNO
- (operand_reg[nop])]
- .last_reload);
-
- /* The value of reload_sum has sense only if we
- process insns in their order. It happens only on
- the first constraints sub-pass when we do most of
- reload work. */
- if (lra_constraint_iter == 1 && last_reload > bb_reload_num)
- reload_sum += last_reload - bb_reload_num;
- }
- /* If this is a constant that is reloaded into the
- desired class by copying it to memory first, count
- that as another reload. This is consistent with
- other code and is required to avoid choosing another
- alternative when the constant is moved into memory.
- Note that the test here is precisely the same as in
- the code below that calls force_const_mem. */
- if (CONST_POOL_OK_P (mode, op)
- && ((targetm.preferred_reload_class
- (op, this_alternative) == NO_REGS)
- || no_input_reloads_p))
- {
- const_to_mem = 1;
- if (! no_regs_p)
- losers++;
- }
-
- /* Alternative loses if it requires a type of reload not
- permitted for this insn. We can always reload
- objects with a REG_UNUSED note. */
- if ((curr_static_id->operand[nop].type != OP_IN
- && no_output_reloads_p
- && ! find_reg_note (curr_insn, REG_UNUSED, op))
- || (curr_static_id->operand[nop].type != OP_OUT
- && no_input_reloads_p && ! const_to_mem)
- || (this_alternative_matches >= 0
- && (no_input_reloads_p
- || (no_output_reloads_p
- && (curr_static_id->operand
- [this_alternative_matches].type != OP_IN)
- && ! find_reg_note (curr_insn, REG_UNUSED,
- no_subreg_reg_operand
- [this_alternative_matches])))))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " alt=%d: No input/output reload -- refuse\n",
- nalt);
- goto fail;
- }
-
- /* Alternative loses if it required class pseudo cannot
- hold value of required mode. Such insns can be
- described by insn definitions with mode iterators. */
- if (GET_MODE (*curr_id->operand_loc[nop]) != VOIDmode
- && ! hard_reg_set_empty_p (this_alternative_set)
- /* It is common practice for constraints to use a
- class which does not have actually enough regs to
- hold the value (e.g. x86 AREG for mode requiring
- more one general reg). Therefore we have 2
- conditions to check that the reload pseudo cannot
- hold the mode value. */
- && (!targetm.hard_regno_mode_ok
- (ira_class_hard_regs[this_alternative][0],
- GET_MODE (*curr_id->operand_loc[nop])))
- /* The above condition is not enough as the first
- reg in ira_class_hard_regs can be not aligned for
- multi-words mode values. */
- && (prohibited_class_reg_set_mode_p
- (this_alternative, this_alternative_set,
- GET_MODE (*curr_id->operand_loc[nop]))))
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " alt=%d: reload pseudo for op %d "
- "cannot hold the mode value -- refuse\n",
- nalt, nop);
- goto fail;
- }
-
- /* Check strong discouragement of reload of non-constant
- into class THIS_ALTERNATIVE. */
- if (! CONSTANT_P (op) && ! no_regs_p
- && (targetm.preferred_reload_class
- (op, this_alternative) == NO_REGS
- || (curr_static_id->operand[nop].type == OP_OUT
- && (targetm.preferred_output_reload_class
- (op, this_alternative) == NO_REGS))))
- {
- if (offmemok && REG_P (op))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Spill pseudo into memory: reject+=3\n",
- nop);
- reject += 3;
- }
- else
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Non-prefered reload: reject+=%d\n",
- nop, LRA_MAX_REJECT);
- reject += LRA_MAX_REJECT;
- }
- }
-
- if (! (MEM_P (op) && offmemok)
- && ! (const_to_mem && constmemok))
- {
- /* We prefer to reload pseudos over reloading other
- things, since such reloads may be able to be
- eliminated later. So bump REJECT in other cases.
- Don't do this in the case where we are forcing a
- constant into memory and it will then win since
- we don't want to have a different alternative
- match then. */
- if (! (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Non-pseudo reload: reject+=2\n",
- nop);
- reject += 2;
- }
-
- if (! no_regs_p)
- reload_nregs
- += ira_reg_class_max_nregs[this_alternative][mode];
-
- if (SMALL_REGISTER_CLASS_P (this_alternative))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Small class reload: reject+=%d\n",
- nop, LRA_LOSER_COST_FACTOR / 2);
- reject += LRA_LOSER_COST_FACTOR / 2;
- }
- }
-
- /* We are trying to spill pseudo into memory. It is
- usually more costly than moving to a hard register
- although it might takes the same number of
- reloads.
-
- Non-pseudo spill may happen also. Suppose a target allows both
- register and memory in the operand constraint alternatives,
- then it's typical that an eliminable register has a substition
- of "base + offset" which can either be reloaded by a simple
- "new_reg <= base + offset" which will match the register
- constraint, or a similar reg addition followed by further spill
- to and reload from memory which will match the memory
- constraint, but this memory spill will be much more costly
- usually.
-
- Code below increases the reject for both pseudo and non-pseudo
- spill. */
- if (no_regs_p
- && !(MEM_P (op) && offmemok)
- && !(REG_P (op) && hard_regno[nop] < 0))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Spill %spseudo into memory: reject+=3\n",
- nop, REG_P (op) ? "" : "Non-");
- reject += 3;
- if (VECTOR_MODE_P (mode))
- {
- /* Spilling vectors into memory is usually more
- costly as they contain big values. */
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Spill vector pseudo: reject+=2\n",
- nop);
- reject += 2;
- }
- }
-
- /* When we use an operand requiring memory in given
- alternative, the insn should write *and* read the
- value to/from memory it is costly in comparison with
- an insn alternative which does not use memory
- (e.g. register or immediate operand). We exclude
- memory operand for such case as we can satisfy the
- memory constraints by reloading address. */
- if (no_regs_p && offmemok && !MEM_P (op))
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " Using memory insn operand %d: reject+=3\n",
- nop);
- reject += 3;
- }
-
- /* If reload requires moving value through secondary
- memory, it will need one more insn at least. */
- if (this_alternative != NO_REGS
- && REG_P (op) && (cl = get_reg_class (REGNO (op))) != NO_REGS
- && ((curr_static_id->operand[nop].type != OP_OUT
- && targetm.secondary_memory_needed (GET_MODE (op), cl,
- this_alternative))
- || (curr_static_id->operand[nop].type != OP_IN
- && (targetm.secondary_memory_needed
- (GET_MODE (op), this_alternative, cl)))))
- losers++;
-
- if (MEM_P (op) && offmemok)
- addr_losers++;
- else
- {
- /* Input reloads can be inherited more often than
- output reloads can be removed, so penalize output
- reloads. */
- if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN)
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Non input pseudo reload: reject++\n",
- nop);
- reject++;
- }
-
- if (curr_static_id->operand[nop].type == OP_INOUT)
- {
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Input/Output reload: reject+=%d\n",
- nop, LRA_LOSER_COST_FACTOR);
- reject += LRA_LOSER_COST_FACTOR;
- }
- }
- }
-
- if (early_clobber_p && ! scratch_p)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " %d Early clobber: reject++\n", nop);
- reject++;
- }
- /* ??? We check early clobbers after processing all operands
- (see loop below) and there we update the costs more.
- Should we update the cost (may be approximately) here
- because of early clobber register reloads or it is a rare
- or non-important thing to be worth to do it. */
- overall = (losers * LRA_LOSER_COST_FACTOR + reject
- - (addr_losers == losers ? static_reject : 0));
- if ((best_losers == 0 || losers != 0) && best_overall < overall)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " alt=%d,overall=%d,losers=%d -- refuse\n",
- nalt, overall, losers);
- goto fail;
- }
-
- if (update_and_check_small_class_inputs (nop, nalt,
- this_alternative))
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " alt=%d, not enough small class regs -- refuse\n",
- nalt);
- goto fail;
- }
- curr_alt[nop] = this_alternative;
- curr_alt_set[nop] = this_alternative_set;
- curr_alt_win[nop] = this_alternative_win;
- curr_alt_match_win[nop] = this_alternative_match_win;
- curr_alt_offmemok[nop] = this_alternative_offmemok;
- curr_alt_matches[nop] = this_alternative_matches;
-
- if (this_alternative_matches >= 0
- && !did_match && !this_alternative_win)
- curr_alt_win[this_alternative_matches] = false;
-
- if (early_clobber_p && operand_reg[nop] != NULL_RTX)
- early_clobbered_nops[early_clobbered_regs_num++] = nop;
- }
-
- if (curr_insn_set != NULL_RTX && n_operands == 2
- /* Prevent processing non-move insns. */
- && (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG
- || SET_SRC (curr_insn_set) == no_subreg_reg_operand[1])
- && ((! curr_alt_win[0] && ! curr_alt_win[1]
- && REG_P (no_subreg_reg_operand[0])
- && REG_P (no_subreg_reg_operand[1])
- && (reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1])
- || reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0])))
- || (! curr_alt_win[0] && curr_alt_win[1]
- && REG_P (no_subreg_reg_operand[1])
- /* Check that we reload memory not the memory
- address. */
- && ! (curr_alt_offmemok[0]
- && MEM_P (no_subreg_reg_operand[0]))
- && reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0]))
- || (curr_alt_win[0] && ! curr_alt_win[1]
- && REG_P (no_subreg_reg_operand[0])
- /* Check that we reload memory not the memory
- address. */
- && ! (curr_alt_offmemok[1]
- && MEM_P (no_subreg_reg_operand[1]))
- && reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1])
- && (! CONST_POOL_OK_P (curr_operand_mode[1],
- no_subreg_reg_operand[1])
- || (targetm.preferred_reload_class
- (no_subreg_reg_operand[1],
- (enum reg_class) curr_alt[1]) != NO_REGS))
- /* If it is a result of recent elimination in move
- insn we can transform it into an add still by
- using this alternative. */
- && GET_CODE (no_subreg_reg_operand[1]) != PLUS
- /* Likewise if the source has been replaced with an
- equivalent value. This only happens once -- the reload
- will use the equivalent value instead of the register it
- replaces -- so there should be no danger of cycling. */
- && !equiv_substition_p[1])))
- {
- /* We have a move insn and a new reload insn will be similar
- to the current insn. We should avoid such situation as
- it results in LRA cycling. */
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " Cycle danger: overall += LRA_MAX_REJECT\n");
- overall += LRA_MAX_REJECT;
- }
- ok_p = true;
- curr_alt_dont_inherit_ops_num = 0;
- for (nop = 0; nop < early_clobbered_regs_num; nop++)
- {
- int i, j, clobbered_hard_regno, first_conflict_j, last_conflict_j;
- HARD_REG_SET temp_set;
-
- i = early_clobbered_nops[nop];
- if ((! curr_alt_win[i] && ! curr_alt_match_win[i])
- || hard_regno[i] < 0)
- continue;
- lra_assert (operand_reg[i] != NULL_RTX);
- clobbered_hard_regno = hard_regno[i];
- CLEAR_HARD_REG_SET (temp_set);
- add_to_hard_reg_set (&temp_set, biggest_mode[i], clobbered_hard_regno);
- first_conflict_j = last_conflict_j = -1;
- for (j = 0; j < n_operands; j++)
- if (j == i
- /* We don't want process insides of match_operator and
- match_parallel because otherwise we would process
- their operands once again generating a wrong
- code. */
- || curr_static_id->operand[j].is_operator)
- continue;
- else if ((curr_alt_matches[j] == i && curr_alt_match_win[j])
- || (curr_alt_matches[i] == j && curr_alt_match_win[i]))
- continue;
- /* If we don't reload j-th operand, check conflicts. */
- else if ((curr_alt_win[j] || curr_alt_match_win[j])
- && uses_hard_regs_p (*curr_id->operand_loc[j], temp_set))
- {
- if (first_conflict_j < 0)
- first_conflict_j = j;
- last_conflict_j = j;
- /* Both the earlyclobber operand and conflicting operand
- cannot both be user defined hard registers. */
- if (HARD_REGISTER_P (operand_reg[i])
- && REG_USERVAR_P (operand_reg[i])
- && operand_reg[j] != NULL_RTX
- && HARD_REGISTER_P (operand_reg[j])
- && REG_USERVAR_P (operand_reg[j]))
- {
- /* For asm, let curr_insn_transform diagnose it. */
- if (INSN_CODE (curr_insn) < 0)
- return false;
- fatal_insn ("unable to generate reloads for "
- "impossible constraints:", curr_insn);
- }
- }
- if (last_conflict_j < 0)
- continue;
-
- /* If an earlyclobber operand conflicts with another non-matching
- operand (ie, they have been assigned the same hard register),
- then it is better to reload the other operand, as there may
- exist yet another operand with a matching constraint associated
- with the earlyclobber operand. However, if one of the operands
- is an explicit use of a hard register, then we must reload the
- other non-hard register operand. */
- if (HARD_REGISTER_P (operand_reg[i])
- || (first_conflict_j == last_conflict_j
- && operand_reg[last_conflict_j] != NULL_RTX
- && !curr_alt_match_win[last_conflict_j]
- && !HARD_REGISTER_P (operand_reg[last_conflict_j])))
- {
- curr_alt_win[last_conflict_j] = false;
- curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]
- = last_conflict_j;
- losers++;
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Conflict early clobber reload: reject--\n",
- i);
- }
- else
- {
- /* We need to reload early clobbered register and the
- matched registers. */
- for (j = 0; j < n_operands; j++)
- if (curr_alt_matches[j] == i)
- {
- curr_alt_match_win[j] = false;
- losers++;
- overall += LRA_LOSER_COST_FACTOR;
- }
- if (! curr_alt_match_win[i])
- curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i;
- else
- {
- /* Remember pseudos used for match reloads are never
- inherited. */
- lra_assert (curr_alt_matches[i] >= 0);
- curr_alt_win[curr_alt_matches[i]] = false;
- }
- curr_alt_win[i] = curr_alt_match_win[i] = false;
- losers++;
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Matched conflict early clobber reloads: "
- "reject--\n",
- i);
- }
- /* Early clobber was already reflected in REJECT. */
- if (!matching_early_clobber[i])
- {
- lra_assert (reject > 0);
- reject--;
- matching_early_clobber[i] = 1;
- }
- overall += LRA_LOSER_COST_FACTOR - 1;
- }
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " alt=%d,overall=%d,losers=%d,rld_nregs=%d\n",
- nalt, overall, losers, reload_nregs);
-
- /* If this alternative can be made to work by reloading, and it
- needs less reloading than the others checked so far, record
- it as the chosen goal for reloading. */
- if ((best_losers != 0 && losers == 0)
- || (((best_losers == 0 && losers == 0)
- || (best_losers != 0 && losers != 0))
- && (best_overall > overall
- || (best_overall == overall
- /* If the cost of the reloads is the same,
- prefer alternative which requires minimal
- number of reload regs. */
- && (reload_nregs < best_reload_nregs
- || (reload_nregs == best_reload_nregs
- && (best_reload_sum < reload_sum
- || (best_reload_sum == reload_sum
- && nalt < goal_alt_number))))))))
- {
- for (nop = 0; nop < n_operands; nop++)
- {
- goal_alt_win[nop] = curr_alt_win[nop];
- goal_alt_match_win[nop] = curr_alt_match_win[nop];
- goal_alt_matches[nop] = curr_alt_matches[nop];
- goal_alt[nop] = curr_alt[nop];
- goal_alt_offmemok[nop] = curr_alt_offmemok[nop];
- }
- goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num;
- for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++)
- goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop];
- goal_alt_swapped = curr_swapped;
- best_overall = overall;
- best_losers = losers;
- best_reload_nregs = reload_nregs;
- best_reload_sum = reload_sum;
- goal_alt_number = nalt;
- }
- if (losers == 0)
- /* Everything is satisfied. Do not process alternatives
- anymore. */
- break;
- fail:
- ;
- }
- return ok_p;
-}
-
-/* Make reload base reg from address AD. */
-static rtx
-base_to_reg (struct address_info *ad)
-{
- enum reg_class cl;
- int code = -1;
- rtx new_inner = NULL_RTX;
- rtx new_reg = NULL_RTX;
- rtx_insn *insn;
- rtx_insn *last_insn = get_last_insn();
-
- lra_assert (ad->disp == ad->disp_term);
- cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
- get_index_code (ad));
- new_reg = lra_create_new_reg (GET_MODE (*ad->base), NULL_RTX,
- cl, "base");
- new_inner = simplify_gen_binary (PLUS, GET_MODE (new_reg), new_reg,
- ad->disp_term == NULL
- ? const0_rtx
- : *ad->disp_term);
- if (!valid_address_p (ad->mode, new_inner, ad->as))
- return NULL_RTX;
- insn = emit_insn (gen_rtx_SET (new_reg, *ad->base));
- code = recog_memoized (insn);
- if (code < 0)
- {
- delete_insns_since (last_insn);
- return NULL_RTX;
- }
-
- return new_inner;
-}
-
-/* Make reload base reg + DISP from address AD. Return the new pseudo. */
-static rtx
-base_plus_disp_to_reg (struct address_info *ad, rtx disp)
-{
- enum reg_class cl;
- rtx new_reg;
-
- lra_assert (ad->base == ad->base_term);
- cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
- get_index_code (ad));
- new_reg = lra_create_new_reg (GET_MODE (*ad->base_term), NULL_RTX,
- cl, "base + disp");
- lra_emit_add (new_reg, *ad->base_term, disp);
- return new_reg;
-}
-
-/* Make reload of index part of address AD. Return the new
- pseudo. */
-static rtx
-index_part_to_reg (struct address_info *ad)
-{
- rtx new_reg;
-
- new_reg = lra_create_new_reg (GET_MODE (*ad->index), NULL_RTX,
- INDEX_REG_CLASS, "index term");
- expand_mult (GET_MODE (*ad->index), *ad->index_term,
- GEN_INT (get_index_scale (ad)), new_reg, 1);
- return new_reg;
-}
-
-/* Return true if we can add a displacement to address AD, even if that
- makes the address invalid. The fix-up code requires any new address
- to be the sum of the BASE_TERM, INDEX and DISP_TERM fields. */
-static bool
-can_add_disp_p (struct address_info *ad)
-{
- return (!ad->autoinc_p
- && ad->segment == NULL
- && ad->base == ad->base_term
- && ad->disp == ad->disp_term);
-}
-
-/* Make equiv substitution in address AD. Return true if a substitution
- was made. */
-static bool
-equiv_address_substitution (struct address_info *ad)
-{
- rtx base_reg, new_base_reg, index_reg, new_index_reg, *base_term, *index_term;
- poly_int64 disp;
- HOST_WIDE_INT scale;
- bool change_p;
-
- base_term = strip_subreg (ad->base_term);
- if (base_term == NULL)
- base_reg = new_base_reg = NULL_RTX;
- else
- {
- base_reg = *base_term;
- new_base_reg = get_equiv_with_elimination (base_reg, curr_insn);
- }
- index_term = strip_subreg (ad->index_term);
- if (index_term == NULL)
- index_reg = new_index_reg = NULL_RTX;
- else
- {
- index_reg = *index_term;
- new_index_reg = get_equiv_with_elimination (index_reg, curr_insn);
- }
- if (base_reg == new_base_reg && index_reg == new_index_reg)
- return false;
- disp = 0;
- change_p = false;
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, "Changing address in insn %d ",
- INSN_UID (curr_insn));
- dump_value_slim (lra_dump_file, *ad->outer, 1);
- }
- if (base_reg != new_base_reg)
- {
- poly_int64 offset;
- if (REG_P (new_base_reg))
- {
- *base_term = new_base_reg;
- change_p = true;
- }
- else if (GET_CODE (new_base_reg) == PLUS
- && REG_P (XEXP (new_base_reg, 0))
- && poly_int_rtx_p (XEXP (new_base_reg, 1), &offset)
- && can_add_disp_p (ad))
- {
- disp += offset;
- *base_term = XEXP (new_base_reg, 0);
- change_p = true;
- }
- if (ad->base_term2 != NULL)
- *ad->base_term2 = *ad->base_term;
- }
- if (index_reg != new_index_reg)
- {
- poly_int64 offset;
- if (REG_P (new_index_reg))
- {
- *index_term = new_index_reg;
- change_p = true;
- }
- else if (GET_CODE (new_index_reg) == PLUS
- && REG_P (XEXP (new_index_reg, 0))
- && poly_int_rtx_p (XEXP (new_index_reg, 1), &offset)
- && can_add_disp_p (ad)
- && (scale = get_index_scale (ad)))
- {
- disp += offset * scale;
- *index_term = XEXP (new_index_reg, 0);
- change_p = true;
- }
- }
- if (maybe_ne (disp, 0))
- {
- if (ad->disp != NULL)
- *ad->disp = plus_constant (GET_MODE (*ad->inner), *ad->disp, disp);
- else
- {
- *ad->inner = plus_constant (GET_MODE (*ad->inner), *ad->inner, disp);
- update_address (ad);
- }
- change_p = true;
- }
- if (lra_dump_file != NULL)
- {
- if (! change_p)
- fprintf (lra_dump_file, " -- no change\n");
- else
- {
- fprintf (lra_dump_file, " on equiv ");
- dump_value_slim (lra_dump_file, *ad->outer, 1);
- fprintf (lra_dump_file, "\n");
- }
- }
- return change_p;
-}
-
-/* Skip all modifiers and whitespaces in constraint STR and return the
- result. */
-static const char *
-skip_constraint_modifiers (const char *str)
-{
- for (;;str++)
- switch (*str)
- {
- case '+': case '&' : case '=': case '*': case ' ': case '\t':
- case '$': case '^' : case '%': case '?': case '!':
- break;
- default: return str;
- }
-}
-
-/* Major function to make reloads for an address in operand NOP or
- check its correctness (If CHECK_ONLY_P is true). The supported
- cases are:
-
- 1) an address that existed before LRA started, at which point it
- must have been valid. These addresses are subject to elimination
- and may have become invalid due to the elimination offset being out
- of range.
-
- 2) an address created by forcing a constant to memory
- (force_const_to_mem). The initial form of these addresses might
- not be valid, and it is this function's job to make them valid.
-
- 3) a frame address formed from a register and a (possibly zero)
- constant offset. As above, these addresses might not be valid and
- this function must make them so.
-
- Add reloads to the lists *BEFORE and *AFTER. We might need to add
- reloads to *AFTER because of inc/dec, {pre, post} modify in the
- address. Return true for any RTL change.
-
- The function is a helper function which does not produce all
- transformations (when CHECK_ONLY_P is false) which can be
- necessary. It does just basic steps. To do all necessary
- transformations use function process_address. */
-static bool
-process_address_1 (int nop, bool check_only_p,
- rtx_insn **before, rtx_insn **after)
-{
- struct address_info ad;
- rtx new_reg;
- HOST_WIDE_INT scale;
- rtx op = *curr_id->operand_loc[nop];
- rtx mem = extract_mem_from_operand (op);
- const char *constraint;
- enum constraint_num cn;
- bool change_p = false;
-
- if (MEM_P (mem)
- && GET_MODE (mem) == BLKmode
- && GET_CODE (XEXP (mem, 0)) == SCRATCH)
- return false;
-
- constraint
- = skip_constraint_modifiers (curr_static_id->operand[nop].constraint);
- if (IN_RANGE (constraint[0], '0', '9'))
- {
- char *end;
- unsigned long dup = strtoul (constraint, &end, 10);
- constraint
- = skip_constraint_modifiers (curr_static_id->operand[dup].constraint);
- }
- cn = lookup_constraint (*constraint == '\0' ? "X" : constraint);
- /* If we have several alternatives or/and several constraints in an
- alternative and we can not say at this stage what constraint will be used,
- use unknown constraint. The exception is an address constraint. If
- operand has one address constraint, probably all others constraints are
- address ones. */
- if (constraint[0] != '\0' && get_constraint_type (cn) != CT_ADDRESS
- && *skip_constraint_modifiers (constraint
- + CONSTRAINT_LEN (constraint[0],
- constraint)) != '\0')
- cn = CONSTRAINT__UNKNOWN;
- if (insn_extra_address_constraint (cn)
- /* When we find an asm operand with an address constraint that
- doesn't satisfy address_operand to begin with, we clear
- is_address, so that we don't try to make a non-address fit.
- If the asm statement got this far, it's because other
- constraints are available, and we'll use them, disregarding
- the unsatisfiable address ones. */
- && curr_static_id->operand[nop].is_address)
- decompose_lea_address (&ad, curr_id->operand_loc[nop]);
- /* Do not attempt to decompose arbitrary addresses generated by combine
- for asm operands with loose constraints, e.g 'X'.
- Need to extract memory from op for special memory constraint,
- i.e. bcst_mem_operand in i386 backend. */
- else if (MEM_P (mem)
- && !(INSN_CODE (curr_insn) < 0
- && get_constraint_type (cn) == CT_FIXED_FORM
- && constraint_satisfied_p (op, cn)))
- decompose_mem_address (&ad, mem);
- else if (GET_CODE (op) == SUBREG
- && MEM_P (SUBREG_REG (op)))
- decompose_mem_address (&ad, SUBREG_REG (op));
- else
- return false;
- /* If INDEX_REG_CLASS is assigned to base_term already and isn't to
- index_term, swap them so to avoid assigning INDEX_REG_CLASS to both
- when INDEX_REG_CLASS is a single register class. */
- if (ad.base_term != NULL
- && ad.index_term != NULL
- && ira_class_hard_regs_num[INDEX_REG_CLASS] == 1
- && REG_P (*ad.base_term)
- && REG_P (*ad.index_term)
- && in_class_p (*ad.base_term, INDEX_REG_CLASS, NULL)
- && ! in_class_p (*ad.index_term, INDEX_REG_CLASS, NULL))
- {
- std::swap (ad.base, ad.index);
- std::swap (ad.base_term, ad.index_term);
- }
- if (! check_only_p)
- change_p = equiv_address_substitution (&ad);
- if (ad.base_term != NULL
- && (process_addr_reg
- (ad.base_term, check_only_p, before,
- (ad.autoinc_p
- && !(REG_P (*ad.base_term)
- && find_regno_note (curr_insn, REG_DEAD,
- REGNO (*ad.base_term)) != NULL_RTX)
- ? after : NULL),
- base_reg_class (ad.mode, ad.as, ad.base_outer_code,
- get_index_code (&ad)))))
- {
- change_p = true;
- if (ad.base_term2 != NULL)
- *ad.base_term2 = *ad.base_term;
- }
- if (ad.index_term != NULL
- && process_addr_reg (ad.index_term, check_only_p,
- before, NULL, INDEX_REG_CLASS))
- change_p = true;
-
- /* Target hooks sometimes don't treat extra-constraint addresses as
- legitimate address_operands, so handle them specially. */
- if (insn_extra_address_constraint (cn)
- && satisfies_address_constraint_p (&ad, cn))
- return change_p;
-
- if (check_only_p)
- return change_p;
-
- /* There are three cases where the shape of *AD.INNER may now be invalid:
-
- 1) the original address was valid, but either elimination or
- equiv_address_substitution was applied and that made
- the address invalid.
-
- 2) the address is an invalid symbolic address created by
- force_const_to_mem.
-
- 3) the address is a frame address with an invalid offset.
-
- 4) the address is a frame address with an invalid base.
-
- All these cases involve a non-autoinc address, so there is no
- point revalidating other types. */
- if (ad.autoinc_p || valid_address_p (op, &ad, cn))
- return change_p;
-
- /* Any index existed before LRA started, so we can assume that the
- presence and shape of the index is valid. */
- push_to_sequence (*before);
- lra_assert (ad.disp == ad.disp_term);
- if (ad.base == NULL)
- {
- if (ad.index == NULL)
- {
- rtx_insn *insn;
- rtx_insn *last = get_last_insn ();
- int code = -1;
- enum reg_class cl = base_reg_class (ad.mode, ad.as,
- SCRATCH, SCRATCH);
- rtx addr = *ad.inner;
-
- new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "addr");
- if (HAVE_lo_sum)
- {
- /* addr => lo_sum (new_base, addr), case (2) above. */
- insn = emit_insn (gen_rtx_SET
- (new_reg,
- gen_rtx_HIGH (Pmode, copy_rtx (addr))));
- code = recog_memoized (insn);
- if (code >= 0)
- {
- *ad.inner = gen_rtx_LO_SUM (Pmode, new_reg, addr);
- if (!valid_address_p (op, &ad, cn))
- {
- /* Try to put lo_sum into register. */
- insn = emit_insn (gen_rtx_SET
- (new_reg,
- gen_rtx_LO_SUM (Pmode, new_reg, addr)));
- code = recog_memoized (insn);
- if (code >= 0)
- {
- *ad.inner = new_reg;
- if (!valid_address_p (op, &ad, cn))
- {
- *ad.inner = addr;
- code = -1;
- }
- }
-
- }
- }
- if (code < 0)
- delete_insns_since (last);
- }
-
- if (code < 0)
- {
- /* addr => new_base, case (2) above. */
- lra_emit_move (new_reg, addr);
-
- for (insn = last == NULL_RTX ? get_insns () : NEXT_INSN (last);
- insn != NULL_RTX;
- insn = NEXT_INSN (insn))
- if (recog_memoized (insn) < 0)
- break;
- if (insn != NULL_RTX)
- {
- /* Do nothing if we cannot generate right insns.
- This is analogous to reload pass behavior. */
- delete_insns_since (last);
- end_sequence ();
- return false;
- }
- *ad.inner = new_reg;
- }
- }
- else
- {
- /* index * scale + disp => new base + index * scale,
- case (1) above. */
- enum reg_class cl = base_reg_class (ad.mode, ad.as, PLUS,
- GET_CODE (*ad.index));
-
- lra_assert (INDEX_REG_CLASS != NO_REGS);
- new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
- lra_emit_move (new_reg, *ad.disp);
- *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
- new_reg, *ad.index);
- }
- }
- else if (ad.index == NULL)
- {
- int regno;
- enum reg_class cl;
- rtx set;
- rtx_insn *insns, *last_insn;
- /* Try to reload base into register only if the base is invalid
- for the address but with valid offset, case (4) above. */
- start_sequence ();
- new_reg = base_to_reg (&ad);
-
- /* base + disp => new base, cases (1) and (3) above. */
- /* Another option would be to reload the displacement into an
- index register. However, postreload has code to optimize
- address reloads that have the same base and different
- displacements, so reloading into an index register would
- not necessarily be a win. */
- if (new_reg == NULL_RTX)
- {
- /* See if the target can split the displacement into a
- legitimate new displacement from a local anchor. */
- gcc_assert (ad.disp == ad.disp_term);
- poly_int64 orig_offset;
- rtx offset1, offset2;
- if (poly_int_rtx_p (*ad.disp, &orig_offset)
- && targetm.legitimize_address_displacement (&offset1, &offset2,
- orig_offset,
- ad.mode))
- {
- new_reg = base_plus_disp_to_reg (&ad, offset1);
- new_reg = gen_rtx_PLUS (GET_MODE (new_reg), new_reg, offset2);
- }
- else
- new_reg = base_plus_disp_to_reg (&ad, *ad.disp);
- }
- insns = get_insns ();
- last_insn = get_last_insn ();
- /* If we generated at least two insns, try last insn source as
- an address. If we succeed, we generate one less insn. */
- if (REG_P (new_reg)
- && last_insn != insns
- && (set = single_set (last_insn)) != NULL_RTX
- && GET_CODE (SET_SRC (set)) == PLUS
- && REG_P (XEXP (SET_SRC (set), 0))
- && CONSTANT_P (XEXP (SET_SRC (set), 1)))
- {
- *ad.inner = SET_SRC (set);
- if (valid_address_p (op, &ad, cn))
- {
- *ad.base_term = XEXP (SET_SRC (set), 0);
- *ad.disp_term = XEXP (SET_SRC (set), 1);
- cl = base_reg_class (ad.mode, ad.as, ad.base_outer_code,
- get_index_code (&ad));
- regno = REGNO (*ad.base_term);
- if (regno >= FIRST_PSEUDO_REGISTER
- && cl != lra_get_allocno_class (regno))
- lra_change_class (regno, cl, " Change to", true);
- new_reg = SET_SRC (set);
- delete_insns_since (PREV_INSN (last_insn));
- }
- }
- end_sequence ();
- emit_insn (insns);
- *ad.inner = new_reg;
- }
- else if (ad.disp_term != NULL)
- {
- /* base + scale * index + disp => new base + scale * index,
- case (1) above. */
- gcc_assert (ad.disp == ad.disp_term);
- new_reg = base_plus_disp_to_reg (&ad, *ad.disp);
- *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
- new_reg, *ad.index);
- }
- else if ((scale = get_index_scale (&ad)) == 1)
- {
- /* The last transformation to one reg will be made in
- curr_insn_transform function. */
- end_sequence ();
- return false;
- }
- else if (scale != 0)
- {
- /* base + scale * index => base + new_reg,
- case (1) above.
- Index part of address may become invalid. For example, we
- changed pseudo on the equivalent memory and a subreg of the
- pseudo onto the memory of different mode for which the scale is
- prohibitted. */
- new_reg = index_part_to_reg (&ad);
- *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
- *ad.base_term, new_reg);
- }
- else
- {
- enum reg_class cl = base_reg_class (ad.mode, ad.as,
- SCRATCH, SCRATCH);
- rtx addr = *ad.inner;
-
- new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "addr");
- /* addr => new_base. */
- lra_emit_move (new_reg, addr);
- *ad.inner = new_reg;
- }
- *before = get_insns ();
- end_sequence ();
- return true;
-}
-
-/* If CHECK_ONLY_P is false, do address reloads until it is necessary.
- Use process_address_1 as a helper function. Return true for any
- RTL changes.
-
- If CHECK_ONLY_P is true, just check address correctness. Return
- false if the address correct. */
-static bool
-process_address (int nop, bool check_only_p,
- rtx_insn **before, rtx_insn **after)
-{
- bool res = false;
-
- while (process_address_1 (nop, check_only_p, before, after))
- {
- if (check_only_p)
- return true;
- res = true;
- }
- return res;
-}
-
-/* Emit insns to reload VALUE into a new register. VALUE is an
- auto-increment or auto-decrement 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
- value being incremented/decremented from.
-
- INC_AMOUNT is the number to increment or decrement by (always
- positive and ignored for POST_MODIFY/PRE_MODIFY).
-
- Return pseudo containing the result. */
-static rtx
-emit_inc (enum reg_class new_rclass, rtx in, rtx value, poly_int64 inc_amount)
-{
- /* REG or MEM to be copied and incremented. */
- rtx incloc = 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;
- rtx result;
- bool plus_p = true;
-
- if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY)
- {
- lra_assert (GET_CODE (XEXP (value, 1)) == PLUS
- || GET_CODE (XEXP (value, 1)) == MINUS);
- lra_assert (rtx_equal_p (XEXP (XEXP (value, 1), 0), XEXP (value, 0)));
- plus_p = GET_CODE (XEXP (value, 1)) == PLUS;
- inc = 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, GET_MODE (value));
- }
-
- if (! post && REG_P (incloc))
- result = incloc;
- else
- result = lra_create_new_reg (GET_MODE (value), value, new_rclass,
- "INC/DEC result");
-
- if (real_in != result)
- {
- /* First copy the location to the result register. */
- lra_assert (REG_P (result));
- emit_insn (gen_move_insn (result, real_in));
- }
-
- /* We suppose that there are insns to add/sub with the constant
- increment permitted in {PRE/POST)_{DEC/INC/MODIFY}. At least the
- old reload worked with this assumption. If the assumption
- becomes wrong, we should use approach in function
- base_plus_disp_to_reg. */
- if (in == value)
- {
- /* See if we can directly increment INCLOC. */
- last = get_last_insn ();
- add_insn = emit_insn (plus_p
- ? gen_add2_insn (incloc, inc)
- : gen_sub2_insn (incloc, inc));
-
- code = recog_memoized (add_insn);
- if (code >= 0)
- {
- if (! post && result != incloc)
- emit_insn (gen_move_insn (result, incloc));
- return result;
- }
- delete_insns_since (last);
- }
-
- /* If couldn't do the increment directly, must increment in RESULT.
- 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 (real_in != result)
- emit_insn (gen_move_insn (result, real_in));
- if (plus_p)
- emit_insn (gen_add2_insn (result, inc));
- else
- emit_insn (gen_sub2_insn (result, inc));
- if (result != incloc)
- emit_insn (gen_move_insn (incloc, result));
- }
- else
- {
- /* Post-increment.
-
- Because this might be a jump insn or a compare, and because
- RESULT may not be available after the insn in an input
- reload, we must do the incrementing before the insn being
- reloaded for.
-
- We have already copied IN to RESULT. Increment the copy in
- RESULT, save that back, then decrement RESULT so it has
- the original value. */
- if (plus_p)
- emit_insn (gen_add2_insn (result, inc));
- else
- emit_insn (gen_sub2_insn (result, inc));
- emit_insn (gen_move_insn (incloc, result));
- /* Restore non-modified value for the result. We prefer this
- way because it does not require an additional hard
- register. */
- if (plus_p)
- {
- poly_int64 offset;
- if (poly_int_rtx_p (inc, &offset))
- emit_insn (gen_add2_insn (result,
- gen_int_mode (-offset,
- GET_MODE (result))));
- else
- emit_insn (gen_sub2_insn (result, inc));
- }
- else
- emit_insn (gen_add2_insn (result, inc));
- }
- return result;
-}
-
-/* Return true if the current move insn does not need processing as we
- already know that it satisfies its constraints. */
-static bool
-simple_move_p (void)
-{
- rtx dest, src;
- enum reg_class dclass, sclass;
-
- lra_assert (curr_insn_set != NULL_RTX);
- dest = SET_DEST (curr_insn_set);
- src = SET_SRC (curr_insn_set);
-
- /* If the instruction has multiple sets we need to process it even if it
- is single_set. This can happen if one or more of the SETs are dead.
- See PR73650. */
- if (multiple_sets (curr_insn))
- return false;
-
- return ((dclass = get_op_class (dest)) != NO_REGS
- && (sclass = get_op_class (src)) != NO_REGS
- /* The backend guarantees that register moves of cost 2
- never need reloads. */
- && targetm.register_move_cost (GET_MODE (src), sclass, dclass) == 2);
- }
-
-/* Swap operands NOP and NOP + 1. */
-static inline void
-swap_operands (int nop)
-{
- std::swap (curr_operand_mode[nop], curr_operand_mode[nop + 1]);
- std::swap (original_subreg_reg_mode[nop], original_subreg_reg_mode[nop + 1]);
- std::swap (*curr_id->operand_loc[nop], *curr_id->operand_loc[nop + 1]);
- std::swap (equiv_substition_p[nop], equiv_substition_p[nop + 1]);
- /* Swap the duplicates too. */
- lra_update_dup (curr_id, nop);
- lra_update_dup (curr_id, nop + 1);
-}
-
-/* Main entry point of the constraint code: search the body of the
- current insn to choose the best alternative. It is mimicking insn
- alternative cost calculation model of former reload pass. That is
- because machine descriptions were written to use this model. This
- model can be changed in future. Make commutative operand exchange
- if it is chosen.
-
- if CHECK_ONLY_P is false, do RTL changes to satisfy the
- constraints. Return true if any change happened during function
- call.
-
- If CHECK_ONLY_P is true then don't do any transformation. Just
- check that the insn satisfies all constraints. If the insn does
- not satisfy any constraint, return true. */
-static bool
-curr_insn_transform (bool check_only_p)
-{
- int i, j, k;
- int n_operands;
- int n_alternatives;
- int n_outputs;
- int commutative;
- signed char goal_alt_matched[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
- signed char match_inputs[MAX_RECOG_OPERANDS + 1];
- signed char outputs[MAX_RECOG_OPERANDS + 1];
- rtx_insn *before, *after;
- bool alt_p = false;
- /* Flag that the insn has been changed through a transformation. */
- bool change_p;
- bool sec_mem_p;
- bool use_sec_mem_p;
- int max_regno_before;
- int reused_alternative_num;
-
- curr_insn_set = single_set (curr_insn);
- if (curr_insn_set != NULL_RTX && simple_move_p ())
- {
- /* We assume that the corresponding insn alternative has no
- earlier clobbers. If it is not the case, don't define move
- cost equal to 2 for the corresponding register classes. */
- lra_set_used_insn_alternative (curr_insn, LRA_NON_CLOBBERED_ALT);
- return false;
- }
-
- no_input_reloads_p = no_output_reloads_p = false;
- goal_alt_number = -1;
- change_p = sec_mem_p = false;
-
- /* CALL_INSNs are not allowed to have any output reloads. */
- if (CALL_P (curr_insn))
- no_output_reloads_p = true;
-
- n_operands = curr_static_id->n_operands;
- n_alternatives = curr_static_id->n_alternatives;
-
- /* Just return "no reloads" if insn has no operands with
- constraints. */
- if (n_operands == 0 || n_alternatives == 0)
- return false;
-
- max_regno_before = max_reg_num ();
-
- for (i = 0; i < n_operands; i++)
- {
- goal_alt_matched[i][0] = -1;
- goal_alt_matches[i] = -1;
- }
-
- commutative = curr_static_id->commutative;
-
- /* Now see what we need for pseudos that didn't get hard regs or got
- the wrong kind of hard reg. For this, we must consider all the
- operands together against the register constraints. */
-
- best_losers = best_overall = INT_MAX;
- best_reload_sum = 0;
-
- curr_swapped = false;
- goal_alt_swapped = false;
-
- if (! check_only_p)
- /* Make equivalence substitution and memory subreg elimination
- before address processing because an address legitimacy can
- depend on memory mode. */
- for (i = 0; i < n_operands; i++)
- {
- rtx op, subst, old;
- bool op_change_p = false;
-
- if (curr_static_id->operand[i].is_operator)
- continue;
-
- old = op = *curr_id->operand_loc[i];
- if (GET_CODE (old) == SUBREG)
- old = SUBREG_REG (old);
- subst = get_equiv_with_elimination (old, curr_insn);
- original_subreg_reg_mode[i] = VOIDmode;
- equiv_substition_p[i] = false;
- if (subst != old)
- {
- equiv_substition_p[i] = true;
- subst = copy_rtx (subst);
- lra_assert (REG_P (old));
- if (GET_CODE (op) != SUBREG)
- *curr_id->operand_loc[i] = subst;
- else
- {
- SUBREG_REG (op) = subst;
- if (GET_MODE (subst) == VOIDmode)
- original_subreg_reg_mode[i] = GET_MODE (old);
- }
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- "Changing pseudo %d in operand %i of insn %u on equiv ",
- REGNO (old), i, INSN_UID (curr_insn));
- dump_value_slim (lra_dump_file, subst, 1);
- fprintf (lra_dump_file, "\n");
- }
- op_change_p = change_p = true;
- }
- if (simplify_operand_subreg (i, GET_MODE (old)) || op_change_p)
- {
- change_p = true;
- lra_update_dup (curr_id, i);
- }
- }
-
- /* Reload address registers and displacements. We do it before
- finding an alternative because of memory constraints. */
- before = after = NULL;
- for (i = 0; i < n_operands; i++)
- if (! curr_static_id->operand[i].is_operator
- && process_address (i, check_only_p, &before, &after))
- {
- if (check_only_p)
- return true;
- change_p = true;
- lra_update_dup (curr_id, i);
- }
-
- if (change_p)
- /* If we've changed the instruction then any alternative that
- we chose previously may no longer be valid. */
- lra_set_used_insn_alternative (curr_insn, LRA_UNKNOWN_ALT);
-
- if (! check_only_p && curr_insn_set != NULL_RTX
- && check_and_process_move (&change_p, &sec_mem_p))
- return change_p;
-
- try_swapped:
-
- reused_alternative_num = check_only_p ? LRA_UNKNOWN_ALT : curr_id->used_insn_alternative;
- if (lra_dump_file != NULL && reused_alternative_num >= 0)
- fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n",
- reused_alternative_num, INSN_UID (curr_insn));
-
- if (process_alt_operands (reused_alternative_num))
- alt_p = true;
-
- if (check_only_p)
- return ! alt_p || best_losers != 0;
-
- /* If insn is commutative (it's safe to exchange a certain pair of
- operands) then we need to try each alternative twice, the second
- time matching those two operands as if we had exchanged them. To
- do this, really exchange them in operands.
-
- If we have just tried the alternatives the second time, return
- operands to normal and drop through. */
-
- if (reused_alternative_num < 0 && commutative >= 0)
- {
- curr_swapped = !curr_swapped;
- if (curr_swapped)
- {
- swap_operands (commutative);
- goto try_swapped;
- }
- else
- swap_operands (commutative);
- }
-
- if (! alt_p && ! sec_mem_p)
- {
- /* No alternative works with reloads?? */
- if (INSN_CODE (curr_insn) >= 0)
- fatal_insn ("unable to generate reloads for:", curr_insn);
- error_for_asm (curr_insn,
- "inconsistent operand constraints in an %<asm%>");
- lra_asm_error_p = true;
- if (! JUMP_P (curr_insn))
- {
- /* Avoid further trouble with this insn. Don't generate use
- pattern here as we could use the insn SP offset. */
- lra_set_insn_deleted (curr_insn);
- }
- else
- {
- lra_invalidate_insn_data (curr_insn);
- ira_nullify_asm_goto (curr_insn);
- lra_update_insn_regno_info (curr_insn);
- }
- return true;
- }
-
- /* If the best alternative is with operands 1 and 2 swapped, swap
- them. Update the operand numbers of any reloads already
- pushed. */
-
- if (goal_alt_swapped)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Commutative operand exchange in insn %u\n",
- INSN_UID (curr_insn));
-
- /* Swap the duplicates too. */
- swap_operands (commutative);
- change_p = true;
- }
-
- /* Some targets' TARGET_SECONDARY_MEMORY_NEEDED (e.g. x86) are defined
- too conservatively. So we use the secondary memory only if there
- is no any alternative without reloads. */
- use_sec_mem_p = false;
- if (! alt_p)
- use_sec_mem_p = true;
- else if (sec_mem_p)
- {
- for (i = 0; i < n_operands; i++)
- if (! goal_alt_win[i] && ! goal_alt_match_win[i])
- break;
- use_sec_mem_p = i < n_operands;
- }
-
- if (use_sec_mem_p)
- {
- int in = -1, out = -1;
- rtx new_reg, src, dest, rld;
- machine_mode sec_mode, rld_mode;
-
- lra_assert (curr_insn_set != NULL_RTX && sec_mem_p);
- dest = SET_DEST (curr_insn_set);
- src = SET_SRC (curr_insn_set);
- for (i = 0; i < n_operands; i++)
- if (*curr_id->operand_loc[i] == dest)
- out = i;
- else if (*curr_id->operand_loc[i] == src)
- in = i;
- for (i = 0; i < curr_static_id->n_dups; i++)
- if (out < 0 && *curr_id->dup_loc[i] == dest)
- out = curr_static_id->dup_num[i];
- else if (in < 0 && *curr_id->dup_loc[i] == src)
- in = curr_static_id->dup_num[i];
- lra_assert (out >= 0 && in >= 0
- && curr_static_id->operand[out].type == OP_OUT
- && curr_static_id->operand[in].type == OP_IN);
- rld = partial_subreg_p (GET_MODE (src), GET_MODE (dest)) ? src : dest;
- rld_mode = GET_MODE (rld);
- sec_mode = targetm.secondary_memory_needed_mode (rld_mode);
- new_reg = lra_create_new_reg (sec_mode, NULL_RTX,
- NO_REGS, "secondary");
- /* If the mode is changed, it should be wider. */
- lra_assert (!partial_subreg_p (sec_mode, rld_mode));
- if (sec_mode != rld_mode)
- {
- /* If the target says specifically to use another mode for
- secondary memory moves we cannot reuse the original
- insn. */
- after = emit_spill_move (false, new_reg, dest);
- lra_process_new_insns (curr_insn, NULL, after,
- "Inserting the sec. move");
- /* We may have non null BEFORE here (e.g. after address
- processing. */
- push_to_sequence (before);
- before = emit_spill_move (true, new_reg, src);
- emit_insn (before);
- before = get_insns ();
- end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL, "Changing on");
- lra_set_insn_deleted (curr_insn);
- }
- else if (dest == rld)
- {
- *curr_id->operand_loc[out] = new_reg;
- lra_update_dup (curr_id, out);
- after = emit_spill_move (false, new_reg, dest);
- lra_process_new_insns (curr_insn, NULL, after,
- "Inserting the sec. move");
- }
- else
- {
- *curr_id->operand_loc[in] = new_reg;
- lra_update_dup (curr_id, in);
- /* See comments above. */
- push_to_sequence (before);
- before = emit_spill_move (true, new_reg, src);
- emit_insn (before);
- before = get_insns ();
- end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL,
- "Inserting the sec. move");
- }
- lra_update_insn_regno_info (curr_insn);
- return true;
- }
-
- lra_assert (goal_alt_number >= 0);
- lra_set_used_insn_alternative (curr_insn, goal_alt_number);
-
- if (lra_dump_file != NULL)
- {
- const char *p;
-
- fprintf (lra_dump_file, " Choosing alt %d in insn %u:",
- goal_alt_number, INSN_UID (curr_insn));
- for (i = 0; i < n_operands; i++)
- {
- p = (curr_static_id->operand_alternative
- [goal_alt_number * n_operands + i].constraint);
- if (*p == '\0')
- continue;
- fprintf (lra_dump_file, " (%d) ", i);
- for (; *p != '\0' && *p != ',' && *p != '#'; p++)
- fputc (*p, lra_dump_file);
- }
- if (INSN_CODE (curr_insn) >= 0
- && (p = get_insn_name (INSN_CODE (curr_insn))) != NULL)
- fprintf (lra_dump_file, " {%s}", p);
- if (maybe_ne (curr_id->sp_offset, 0))
- {
- fprintf (lra_dump_file, " (sp_off=");
- print_dec (curr_id->sp_offset, lra_dump_file);
- fprintf (lra_dump_file, ")");
- }
- fprintf (lra_dump_file, "\n");
- }
-
- /* Right now, for any pair of operands I and J that are required to
- match, with J < I, goal_alt_matches[I] is J. Add I to
- goal_alt_matched[J]. */
-
- for (i = 0; i < n_operands; i++)
- if ((j = goal_alt_matches[i]) >= 0)
- {
- for (k = 0; goal_alt_matched[j][k] >= 0; k++)
- ;
- /* We allow matching one output operand and several input
- operands. */
- lra_assert (k == 0
- || (curr_static_id->operand[j].type == OP_OUT
- && curr_static_id->operand[i].type == OP_IN
- && (curr_static_id->operand
- [goal_alt_matched[j][0]].type == OP_IN)));
- goal_alt_matched[j][k] = i;
- goal_alt_matched[j][k + 1] = -1;
- }
-
- for (i = 0; i < n_operands; i++)
- goal_alt_win[i] |= goal_alt_match_win[i];
-
- /* Any constants that aren't allowed and can't be reloaded into
- registers are here changed into memory references. */
- for (i = 0; i < n_operands; i++)
- if (goal_alt_win[i])
- {
- int regno;
- enum reg_class new_class;
- rtx reg = *curr_id->operand_loc[i];
-
- if (GET_CODE (reg) == SUBREG)
- reg = SUBREG_REG (reg);
-
- if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER)
- {
- bool ok_p = in_class_p (reg, goal_alt[i], &new_class);
-
- if (new_class != NO_REGS && get_reg_class (regno) != new_class)
- {
- lra_assert (ok_p);
- lra_change_class (regno, new_class, " Change to", true);
- }
- }
- }
- else
- {
- const char *constraint;
- char c;
- rtx op = *curr_id->operand_loc[i];
- rtx subreg = NULL_RTX;
- machine_mode mode = curr_operand_mode[i];
-
- if (GET_CODE (op) == SUBREG)
- {
- subreg = op;
- op = SUBREG_REG (op);
- mode = GET_MODE (op);
- }
-
- if (CONST_POOL_OK_P (mode, op)
- && ((targetm.preferred_reload_class
- (op, (enum reg_class) goal_alt[i]) == NO_REGS)
- || no_input_reloads_p))
- {
- rtx tem = force_const_mem (mode, op);
-
- change_p = true;
- if (subreg != NULL_RTX)
- tem = gen_rtx_SUBREG (mode, tem, SUBREG_BYTE (subreg));
-
- *curr_id->operand_loc[i] = tem;
- lra_update_dup (curr_id, i);
- process_address (i, false, &before, &after);
-
- /* If the alternative accepts constant pool refs directly
- there will be no reload needed at all. */
- if (subreg != NULL_RTX)
- continue;
- /* Skip alternatives before the one requested. */
- constraint = (curr_static_id->operand_alternative
- [goal_alt_number * n_operands + i].constraint);
- for (;
- (c = *constraint) && c != ',' && c != '#';
- constraint += CONSTRAINT_LEN (c, constraint))
- {
- enum constraint_num cn = lookup_constraint (constraint);
- if ((insn_extra_memory_constraint (cn)
- || insn_extra_special_memory_constraint (cn)
- || insn_extra_relaxed_memory_constraint (cn))
- && satisfies_memory_constraint_p (tem, cn))
- break;
- }
- if (c == '\0' || c == ',' || c == '#')
- continue;
-
- goal_alt_win[i] = true;
- }
- }
-
- n_outputs = 0;
- for (i = 0; i < n_operands; i++)
- if (curr_static_id->operand[i].type == OP_OUT)
- outputs[n_outputs++] = i;
- outputs[n_outputs] = -1;
- for (i = 0; i < n_operands; i++)
- {
- int regno;
- bool optional_p = false;
- rtx old, new_reg;
- rtx op = *curr_id->operand_loc[i];
-
- if (goal_alt_win[i])
- {
- if (goal_alt[i] == NO_REGS
- && REG_P (op)
- /* When we assign NO_REGS it means that we will not
- assign a hard register to the scratch pseudo by
- assigment pass and the scratch pseudo will be
- spilled. Spilled scratch pseudos are transformed
- back to scratches at the LRA end. */
- && ira_former_scratch_operand_p (curr_insn, i)
- && ira_former_scratch_p (REGNO (op)))
- {
- int regno = REGNO (op);
- lra_change_class (regno, NO_REGS, " Change to", true);
- if (lra_get_regno_hard_regno (regno) >= 0)
- /* We don't have to mark all insn affected by the
- spilled pseudo as there is only one such insn, the
- current one. */
- reg_renumber[regno] = -1;
- lra_assert (bitmap_single_bit_set_p
- (&lra_reg_info[REGNO (op)].insn_bitmap));
- }
- /* We can do an optional reload. If the pseudo got a hard
- reg, we might improve the code through inheritance. If
- it does not get a hard register we coalesce memory/memory
- moves later. Ignore move insns to avoid cycling. */
- if (! lra_simple_p
- && lra_undo_inheritance_iter < LRA_MAX_INHERITANCE_PASSES
- && goal_alt[i] != NO_REGS && REG_P (op)
- && (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER
- && regno < new_regno_start
- && ! ira_former_scratch_p (regno)
- && reg_renumber[regno] < 0
- /* Check that the optional reload pseudo will be able to
- hold given mode value. */
- && ! (prohibited_class_reg_set_mode_p
- (goal_alt[i], reg_class_contents[goal_alt[i]],
- PSEUDO_REGNO_MODE (regno)))
- && (curr_insn_set == NULL_RTX
- || !((REG_P (SET_SRC (curr_insn_set))
- || MEM_P (SET_SRC (curr_insn_set))
- || GET_CODE (SET_SRC (curr_insn_set)) == SUBREG)
- && (REG_P (SET_DEST (curr_insn_set))
- || MEM_P (SET_DEST (curr_insn_set))
- || GET_CODE (SET_DEST (curr_insn_set)) == SUBREG))))
- optional_p = true;
- else if (goal_alt_matched[i][0] != -1
- && curr_static_id->operand[i].type == OP_OUT
- && (curr_static_id->operand_alternative
- [goal_alt_number * n_operands + i].earlyclobber)
- && REG_P (op))
- {
- for (j = 0; goal_alt_matched[i][j] != -1; j++)
- {
- rtx op2 = *curr_id->operand_loc[goal_alt_matched[i][j]];
-
- if (REG_P (op2) && REGNO (op) != REGNO (op2))
- break;
- }
- if (goal_alt_matched[i][j] != -1)
- {
- /* Generate reloads for different output and matched
- input registers. This is the easiest way to avoid
- creation of non-existing register conflicts in
- lra-lives.c. */
- match_reload (i, goal_alt_matched[i], outputs, goal_alt[i], &before,
- &after, TRUE);
- }
- continue;
- }
- else
- continue;
- }
-
- /* Operands that match previous ones have already been handled. */
- if (goal_alt_matches[i] >= 0)
- continue;
-
- /* We should not have an operand with a non-offsettable address
- appearing where an offsettable address will do. It also may
- be a case when the address should be special in other words
- not a general one (e.g. it needs no index reg). */
- if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i] && MEM_P (op))
- {
- enum reg_class rclass;
- rtx *loc = &XEXP (op, 0);
- enum rtx_code code = GET_CODE (*loc);
-
- push_to_sequence (before);
- rclass = base_reg_class (GET_MODE (op), MEM_ADDR_SPACE (op),
- MEM, SCRATCH);
- if (GET_RTX_CLASS (code) == RTX_AUTOINC)
- new_reg = emit_inc (rclass, *loc, *loc,
- /* This value does not matter for MODIFY. */
- GET_MODE_SIZE (GET_MODE (op)));
- else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, FALSE,
- "offsetable address", &new_reg))
- {
- rtx addr = *loc;
- enum rtx_code code = GET_CODE (addr);
- bool align_p = false;
-
- if (code == AND && CONST_INT_P (XEXP (addr, 1)))
- {
- /* (and ... (const_int -X)) is used to align to X bytes. */
- align_p = true;
- addr = XEXP (*loc, 0);
- }
- else
- addr = canonicalize_reload_addr (addr);
-
- lra_emit_move (new_reg, addr);
- if (align_p)
- emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg), new_reg, XEXP (*loc, 1)));
- }
- before = get_insns ();
- end_sequence ();
- *loc = new_reg;
- lra_update_dup (curr_id, i);
- }
- else if (goal_alt_matched[i][0] == -1)
- {
- machine_mode mode;
- rtx reg, *loc;
- int hard_regno;
- enum op_type type = curr_static_id->operand[i].type;
-
- loc = curr_id->operand_loc[i];
- mode = curr_operand_mode[i];
- if (GET_CODE (*loc) == SUBREG)
- {
- reg = SUBREG_REG (*loc);
- poly_int64 byte = SUBREG_BYTE (*loc);
- if (REG_P (reg)
- /* Strict_low_part requires reloading the register and not
- just the subreg. Likewise for a strict subreg no wider
- than a word for WORD_REGISTER_OPERATIONS targets. */
- && (curr_static_id->operand[i].strict_low
- || (!paradoxical_subreg_p (mode, GET_MODE (reg))
- && (hard_regno
- = get_try_hard_regno (REGNO (reg))) >= 0
- && (simplify_subreg_regno
- (hard_regno,
- GET_MODE (reg), byte, mode) < 0)
- && (goal_alt[i] == NO_REGS
- || (simplify_subreg_regno
- (ira_class_hard_regs[goal_alt[i]][0],
- GET_MODE (reg), byte, mode) >= 0)))
- || (partial_subreg_p (mode, GET_MODE (reg))
- && known_le (GET_MODE_SIZE (GET_MODE (reg)),
- UNITS_PER_WORD)
- && WORD_REGISTER_OPERATIONS)))
- {
- /* An OP_INOUT is required when reloading a subreg of a
- mode wider than a word to ensure that data beyond the
- word being reloaded is preserved. Also automatically
- ensure that strict_low_part reloads are made into
- OP_INOUT which should already be true from the backend
- constraints. */
- if (type == OP_OUT
- && (curr_static_id->operand[i].strict_low
- || read_modify_subreg_p (*loc)))
- type = OP_INOUT;
- loc = &SUBREG_REG (*loc);
- mode = GET_MODE (*loc);
- }
- }
- old = *loc;
- if (get_reload_reg (type, mode, old, goal_alt[i],
- loc != curr_id->operand_loc[i], "", &new_reg)
- && type != OP_OUT)
- {
- push_to_sequence (before);
- lra_emit_move (new_reg, old);
- before = get_insns ();
- end_sequence ();
- }
- *loc = new_reg;
- if (type != OP_IN
- && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX)
- {
- start_sequence ();
- lra_emit_move (type == OP_INOUT ? copy_rtx (old) : old, new_reg);
- emit_insn (after);
- after = get_insns ();
- end_sequence ();
- *loc = new_reg;
- }
- for (j = 0; j < goal_alt_dont_inherit_ops_num; j++)
- if (goal_alt_dont_inherit_ops[j] == i)
- {
- lra_set_regno_unique_value (REGNO (new_reg));
- break;
- }
- lra_update_dup (curr_id, i);
- }
- else if (curr_static_id->operand[i].type == OP_IN
- && (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_OUT
- || (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_INOUT
- && (operands_match_p
- (*curr_id->operand_loc[i],
- *curr_id->operand_loc[goal_alt_matched[i][0]],
- -1)))))
- {
- /* generate reloads for input and matched outputs. */
- match_inputs[0] = i;
- match_inputs[1] = -1;
- match_reload (goal_alt_matched[i][0], match_inputs, outputs,
- goal_alt[i], &before, &after,
- curr_static_id->operand_alternative
- [goal_alt_number * n_operands + goal_alt_matched[i][0]]
- .earlyclobber);
- }
- else if ((curr_static_id->operand[i].type == OP_OUT
- || (curr_static_id->operand[i].type == OP_INOUT
- && (operands_match_p
- (*curr_id->operand_loc[i],
- *curr_id->operand_loc[goal_alt_matched[i][0]],
- -1))))
- && (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_IN))
- /* Generate reloads for output and matched inputs. */
- match_reload (i, goal_alt_matched[i], outputs, goal_alt[i], &before,
- &after, curr_static_id->operand_alternative
- [goal_alt_number * n_operands + i].earlyclobber);
- else if (curr_static_id->operand[i].type == OP_IN
- && (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_IN))
- {
- /* Generate reloads for matched inputs. */
- match_inputs[0] = i;
- for (j = 0; (k = goal_alt_matched[i][j]) >= 0; j++)
- match_inputs[j + 1] = k;
- match_inputs[j + 1] = -1;
- match_reload (-1, match_inputs, outputs, goal_alt[i], &before,
- &after, false);
- }
- else
- /* We must generate code in any case when function
- process_alt_operands decides that it is possible. */
- gcc_unreachable ();
-
- if (optional_p)
- {
- rtx reg = op;
-
- lra_assert (REG_P (reg));
- regno = REGNO (reg);
- op = *curr_id->operand_loc[i]; /* Substitution. */
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- gcc_assert (REG_P (op) && (int) REGNO (op) >= new_regno_start);
- bitmap_set_bit (&lra_optional_reload_pseudos, REGNO (op));
- lra_reg_info[REGNO (op)].restore_rtx = reg;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " Making reload reg %d for reg %d optional\n",
- REGNO (op), regno);
- }
- }
- if (before != NULL_RTX || after != NULL_RTX
- || max_regno_before != max_reg_num ())
- change_p = true;
- if (change_p)
- {
- lra_update_operator_dups (curr_id);
- /* Something changes -- process the insn. */
- lra_update_insn_regno_info (curr_insn);
- }
- lra_process_new_insns (curr_insn, before, after, "Inserting insn reload");
- return change_p;
-}
-
-/* Return true if INSN satisfies all constraints. In other words, no
- reload insns are needed. */
-bool
-lra_constrain_insn (rtx_insn *insn)
-{
- int saved_new_regno_start = new_regno_start;
- int saved_new_insn_uid_start = new_insn_uid_start;
- bool change_p;
-
- curr_insn = insn;
- curr_id = lra_get_insn_recog_data (curr_insn);
- curr_static_id = curr_id->insn_static_data;
- new_insn_uid_start = get_max_uid ();
- new_regno_start = max_reg_num ();
- change_p = curr_insn_transform (true);
- new_regno_start = saved_new_regno_start;
- new_insn_uid_start = saved_new_insn_uid_start;
- return ! change_p;
-}
-
-/* Return true if X is in LIST. */
-static bool
-in_list_p (rtx x, rtx list)
-{
- for (; list != NULL_RTX; list = XEXP (list, 1))
- if (XEXP (list, 0) == x)
- return true;
- return false;
-}
-
-/* Return true if X contains an allocatable hard register (if
- HARD_REG_P) or a (spilled if SPILLED_P) pseudo. */
-static bool
-contains_reg_p (rtx x, bool hard_reg_p, bool spilled_p)
-{
- int i, j;
- const char *fmt;
- enum rtx_code code;
-
- code = GET_CODE (x);
- if (REG_P (x))
- {
- int regno = REGNO (x);
- HARD_REG_SET alloc_regs;
-
- if (hard_reg_p)
- {
- if (regno >= FIRST_PSEUDO_REGISTER)
- regno = lra_get_regno_hard_regno (regno);
- if (regno < 0)
- return false;
- alloc_regs = ~lra_no_alloc_regs;
- return overlaps_hard_reg_set_p (alloc_regs, GET_MODE (x), regno);
- }
- else
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- return false;
- if (! spilled_p)
- return true;
- return lra_get_regno_hard_regno (regno) < 0;
- }
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (contains_reg_p (XEXP (x, i), hard_reg_p, spilled_p))
- return true;
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (contains_reg_p (XVECEXP (x, i, j), hard_reg_p, spilled_p))
- return true;
- }
- }
- return false;
-}
-
-/* Process all regs in location *LOC and change them on equivalent
- substitution. Return true if any change was done. */
-static bool
-loc_equivalence_change_p (rtx *loc)
-{
- rtx subst, reg, x = *loc;
- bool result = false;
- enum rtx_code code = GET_CODE (x);
- const char *fmt;
- int i, j;
-
- if (code == SUBREG)
- {
- reg = SUBREG_REG (x);
- if ((subst = get_equiv_with_elimination (reg, curr_insn)) != reg
- && GET_MODE (subst) == VOIDmode)
- {
- /* We cannot reload debug location. Simplify subreg here
- while we know the inner mode. */
- *loc = simplify_gen_subreg (GET_MODE (x), subst,
- GET_MODE (reg), SUBREG_BYTE (x));
- return true;
- }
- }
- if (code == REG && (subst = get_equiv_with_elimination (x, curr_insn)) != x)
- {
- *loc = subst;
- return true;
- }
-
- /* Scan all the operand sub-expressions. */
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- result = loc_equivalence_change_p (&XEXP (x, i)) || result;
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- result
- = loc_equivalence_change_p (&XVECEXP (x, i, j)) || result;
- }
- return result;
-}
-
-/* Similar to loc_equivalence_change_p, but for use as
- simplify_replace_fn_rtx callback. DATA is insn for which the
- elimination is done. If it null we don't do the elimination. */
-static rtx
-loc_equivalence_callback (rtx loc, const_rtx, void *data)
-{
- if (!REG_P (loc))
- return NULL_RTX;
-
- rtx subst = (data == NULL
- ? get_equiv (loc) : get_equiv_with_elimination (loc, (rtx_insn *) data));
- if (subst != loc)
- return subst;
-
- return NULL_RTX;
-}
-
-/* Maximum number of generated reload insns per an insn. It is for
- preventing this pass cycling in a bug case. */
-#define MAX_RELOAD_INSNS_NUMBER LRA_MAX_INSN_RELOADS
-
-/* The current iteration number of this LRA pass. */
-int lra_constraint_iter;
-
-/* True if we should during assignment sub-pass check assignment
- correctness for all pseudos and spill some of them to correct
- conflicts. It can be necessary when we substitute equiv which
- needs checking register allocation correctness because the
- equivalent value contains allocatable hard registers, or when we
- restore multi-register pseudo, or when we change the insn code and
- its operand became INOUT operand when it was IN one before. */
-bool check_and_force_assignment_correctness_p;
-
-/* Return true if REGNO is referenced in more than one block. */
-static bool
-multi_block_pseudo_p (int regno)
-{
- basic_block bb = NULL;
- unsigned int uid;
- bitmap_iterator bi;
-
- if (regno < FIRST_PSEUDO_REGISTER)
- return false;
-
- EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
- if (bb == NULL)
- bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn);
- else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb)
- return true;
- return false;
-}
-
-/* Return true if LIST contains a deleted insn. */
-static bool
-contains_deleted_insn_p (rtx_insn_list *list)
-{
- for (; list != NULL_RTX; list = list->next ())
- if (NOTE_P (list->insn ())
- && NOTE_KIND (list->insn ()) == NOTE_INSN_DELETED)
- return true;
- return false;
-}
-
-/* Return true if X contains a pseudo dying in INSN. */
-static bool
-dead_pseudo_p (rtx x, rtx_insn *insn)
-{
- int i, j;
- const char *fmt;
- enum rtx_code code;
-
- if (REG_P (x))
- return (insn != NULL_RTX
- && find_regno_note (insn, REG_DEAD, REGNO (x)) != NULL_RTX);
- code = GET_CODE (x);
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (dead_pseudo_p (XEXP (x, i), insn))
- return true;
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (dead_pseudo_p (XVECEXP (x, i, j), insn))
- return true;
- }
- }
- return false;
-}
-
-/* Return true if INSN contains a dying pseudo in INSN right hand
- side. */
-static bool
-insn_rhs_dead_pseudo_p (rtx_insn *insn)
-{
- rtx set = single_set (insn);
-
- gcc_assert (set != NULL);
- return dead_pseudo_p (SET_SRC (set), insn);
-}
-
-/* Return true if any init insn of REGNO contains a dying pseudo in
- insn right hand side. */
-static bool
-init_insn_rhs_dead_pseudo_p (int regno)
-{
- rtx_insn_list *insns = ira_reg_equiv[regno].init_insns;
-
- if (insns == NULL)
- return false;
- for (; insns != NULL_RTX; insns = insns->next ())
- if (insn_rhs_dead_pseudo_p (insns->insn ()))
- return true;
- return false;
-}
-
-/* Return TRUE if REGNO has a reverse equivalence. The equivalence is
- reverse only if we have one init insn with given REGNO as a
- source. */
-static bool
-reverse_equiv_p (int regno)
-{
- rtx_insn_list *insns = ira_reg_equiv[regno].init_insns;
- rtx set;
-
- if (insns == NULL)
- return false;
- if (! INSN_P (insns->insn ())
- || insns->next () != NULL)
- return false;
- if ((set = single_set (insns->insn ())) == NULL_RTX)
- return false;
- return REG_P (SET_SRC (set)) && (int) REGNO (SET_SRC (set)) == regno;
-}
-
-/* Return TRUE if REGNO was reloaded in an equivalence init insn. We
- call this function only for non-reverse equivalence. */
-static bool
-contains_reloaded_insn_p (int regno)
-{
- rtx set;
- rtx_insn_list *list = ira_reg_equiv[regno].init_insns;
-
- for (; list != NULL; list = list->next ())
- if ((set = single_set (list->insn ())) == NULL_RTX
- || ! REG_P (SET_DEST (set))
- || (int) REGNO (SET_DEST (set)) != regno)
- return true;
- return false;
-}
-
-/* Entry function of LRA constraint pass. Return true if the
- constraint pass did change the code. */
-bool
-lra_constraints (bool first_p)
-{
- bool changed_p;
- int i, hard_regno, new_insns_num;
- unsigned int min_len, new_min_len, uid;
- rtx set, x, reg, dest_reg;
- basic_block last_bb;
- bitmap_iterator bi;
-
- lra_constraint_iter++;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "\n********** Local #%d: **********\n\n",
- lra_constraint_iter);
- changed_p = false;
- if (pic_offset_table_rtx
- && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
- check_and_force_assignment_correctness_p = true;
- else if (first_p)
- /* On the first iteration we should check IRA assignment
- correctness. In rare cases, the assignments can be wrong as
- early clobbers operands are ignored in IRA or usages of
- paradoxical sub-registers are not taken into account by
- IRA. */
- check_and_force_assignment_correctness_p = true;
- new_insn_uid_start = get_max_uid ();
- new_regno_start = first_p ? lra_constraint_new_regno_start : max_reg_num ();
- /* Mark used hard regs for target stack size calulations. */
- for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
- if (lra_reg_info[i].nrefs != 0
- && (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
- {
- int j, nregs;
-
- nregs = hard_regno_nregs (hard_regno, lra_reg_info[i].biggest_mode);
- for (j = 0; j < nregs; j++)
- df_set_regs_ever_live (hard_regno + j, true);
- }
- /* Do elimination before the equivalence processing as we can spill
- some pseudos during elimination. */
- lra_eliminate (false, first_p);
- auto_bitmap equiv_insn_bitmap (&reg_obstack);
- for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
- if (lra_reg_info[i].nrefs != 0)
- {
- ira_reg_equiv[i].profitable_p = true;
- reg = regno_reg_rtx[i];
- if (lra_get_regno_hard_regno (i) < 0 && (x = get_equiv (reg)) != reg)
- {
- bool pseudo_p = contains_reg_p (x, false, false);
-
- /* After RTL transformation, we cannot guarantee that
- pseudo in the substitution was not reloaded which might
- make equivalence invalid. For example, in reverse
- equiv of p0
-
- p0 <- ...
- ...
- equiv_mem <- p0
-
- the memory address register was reloaded before the 2nd
- insn. */
- if ((! first_p && pseudo_p)
- /* We don't use DF for compilation speed sake. So it
- is problematic to update live info when we use an
- equivalence containing pseudos in more than one
- BB. */
- || (pseudo_p && multi_block_pseudo_p (i))
- /* If an init insn was deleted for some reason, cancel
- the equiv. We could update the equiv insns after
- transformations including an equiv insn deletion
- but it is not worthy as such cases are extremely
- rare. */
- || contains_deleted_insn_p (ira_reg_equiv[i].init_insns)
- /* If it is not a reverse equivalence, we check that a
- pseudo in rhs of the init insn is not dying in the
- insn. Otherwise, the live info at the beginning of
- the corresponding BB might be wrong after we
- removed the insn. When the equiv can be a
- constant, the right hand side of the init insn can
- be a pseudo. */
- || (! reverse_equiv_p (i)
- && (init_insn_rhs_dead_pseudo_p (i)
- /* If we reloaded the pseudo in an equivalence
- init insn, we cannot remove the equiv init
- insns and the init insns might write into
- const memory in this case. */
- || contains_reloaded_insn_p (i)))
- /* Prevent access beyond equivalent memory for
- paradoxical subregs. */
- || (MEM_P (x)
- && maybe_gt (GET_MODE_SIZE (lra_reg_info[i].biggest_mode),
- GET_MODE_SIZE (GET_MODE (x))))
- || (pic_offset_table_rtx
- && ((CONST_POOL_OK_P (PSEUDO_REGNO_MODE (i), x)
- && (targetm.preferred_reload_class
- (x, lra_get_allocno_class (i)) == NO_REGS))
- || contains_symbol_ref_p (x))))
- ira_reg_equiv[i].defined_p = false;
- if (contains_reg_p (x, false, true))
- ira_reg_equiv[i].profitable_p = false;
- if (get_equiv (reg) != reg)
- bitmap_ior_into (equiv_insn_bitmap, &lra_reg_info[i].insn_bitmap);
- }
- }
- for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
- update_equiv (i);
- /* We should add all insns containing pseudos which should be
- substituted by their equivalences. */
- EXECUTE_IF_SET_IN_BITMAP (equiv_insn_bitmap, 0, uid, bi)
- lra_push_insn_by_uid (uid);
- min_len = lra_insn_stack_length ();
- new_insns_num = 0;
- last_bb = NULL;
- changed_p = false;
- while ((new_min_len = lra_insn_stack_length ()) != 0)
- {
- curr_insn = lra_pop_insn ();
- --new_min_len;
- curr_bb = BLOCK_FOR_INSN (curr_insn);
- if (curr_bb != last_bb)
- {
- last_bb = curr_bb;
- bb_reload_num = lra_curr_reload_num;
- }
- if (min_len > new_min_len)
- {
- min_len = new_min_len;
- new_insns_num = 0;
- }
- if (new_insns_num > MAX_RELOAD_INSNS_NUMBER)
- internal_error
- ("maximum number of generated reload insns per insn achieved (%d)",
- MAX_RELOAD_INSNS_NUMBER);
- new_insns_num++;
- if (DEBUG_INSN_P (curr_insn))
- {
- /* We need to check equivalence in debug insn and change
- pseudo to the equivalent value if necessary. */
- curr_id = lra_get_insn_recog_data (curr_insn);
- if (bitmap_bit_p (equiv_insn_bitmap, INSN_UID (curr_insn)))
- {
- rtx old = *curr_id->operand_loc[0];
- *curr_id->operand_loc[0]
- = simplify_replace_fn_rtx (old, NULL_RTX,
- loc_equivalence_callback, curr_insn);
- if (old != *curr_id->operand_loc[0])
- {
- lra_update_insn_regno_info (curr_insn);
- changed_p = true;
- }
- }
- }
- else if (INSN_P (curr_insn))
- {
- if ((set = single_set (curr_insn)) != NULL_RTX)
- {
- dest_reg = SET_DEST (set);
- /* The equivalence pseudo could be set up as SUBREG in a
- case when it is a call restore insn in a mode
- different from the pseudo mode. */
- if (GET_CODE (dest_reg) == SUBREG)
- dest_reg = SUBREG_REG (dest_reg);
- if ((REG_P (dest_reg)
- && (x = get_equiv (dest_reg)) != dest_reg
- /* Remove insns which set up a pseudo whose value
- cannot be changed. Such insns might be not in
- init_insns because we don't update equiv data
- during insn transformations.
-
- As an example, let suppose that a pseudo got
- hard register and on the 1st pass was not
- changed to equivalent constant. We generate an
- additional insn setting up the pseudo because of
- secondary memory movement. Then the pseudo is
- spilled and we use the equiv constant. In this
- case we should remove the additional insn and
- this insn is not init_insns list. */
- && (! MEM_P (x) || MEM_READONLY_P (x)
- /* Check that this is actually an insn setting
- up the equivalence. */
- || in_list_p (curr_insn,
- ira_reg_equiv
- [REGNO (dest_reg)].init_insns)))
- || (((x = get_equiv (SET_SRC (set))) != SET_SRC (set))
- && in_list_p (curr_insn,
- ira_reg_equiv
- [REGNO (SET_SRC (set))].init_insns)))
- {
- /* This is equiv init insn of pseudo which did not get a
- hard register -- remove the insn. */
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Removing equiv init insn %i (freq=%d)\n",
- INSN_UID (curr_insn),
- REG_FREQ_FROM_BB (BLOCK_FOR_INSN (curr_insn)));
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- if (contains_reg_p (x, true, false))
- check_and_force_assignment_correctness_p = true;
- lra_set_insn_deleted (curr_insn);
- continue;
- }
- }
- curr_id = lra_get_insn_recog_data (curr_insn);
- curr_static_id = curr_id->insn_static_data;
- init_curr_insn_input_reloads ();
- init_curr_operand_mode ();
- if (curr_insn_transform (false))
- changed_p = true;
- /* Check non-transformed insns too for equiv change as USE
- or CLOBBER don't need reloads but can contain pseudos
- being changed on their equivalences. */
- else if (bitmap_bit_p (equiv_insn_bitmap, INSN_UID (curr_insn))
- && loc_equivalence_change_p (&PATTERN (curr_insn)))
- {
- lra_update_insn_regno_info (curr_insn);
- changed_p = true;
- }
- }
- }
-
- /* If we used a new hard regno, changed_p should be true because the
- hard reg is assigned to a new pseudo. */
- if (flag_checking && !changed_p)
- {
- for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
- if (lra_reg_info[i].nrefs != 0
- && (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
- {
- int j, nregs = hard_regno_nregs (hard_regno,
- PSEUDO_REGNO_MODE (i));
-
- for (j = 0; j < nregs; j++)
- lra_assert (df_regs_ever_live_p (hard_regno + j));
- }
- }
- return changed_p;
-}
-
-static void initiate_invariants (void);
-static void finish_invariants (void);
-
-/* Initiate the LRA constraint pass. It is done once per
- function. */
-void
-lra_constraints_init (void)
-{
- initiate_invariants ();
-}
-
-/* Finalize the LRA constraint pass. It is done once per
- function. */
-void
-lra_constraints_finish (void)
-{
- finish_invariants ();
-}
-
-
-
-/* Structure describes invariants for ineheritance. */
-struct lra_invariant
-{
- /* The order number of the invariant. */
- int num;
- /* The invariant RTX. */
- rtx invariant_rtx;
- /* The origin insn of the invariant. */
- rtx_insn *insn;
-};
-
-typedef lra_invariant invariant_t;
-typedef invariant_t *invariant_ptr_t;
-typedef const invariant_t *const_invariant_ptr_t;
-
-/* Pointer to the inheritance invariants. */
-static vec<invariant_ptr_t> invariants;
-
-/* Allocation pool for the invariants. */
-static object_allocator<lra_invariant> *invariants_pool;
-
-/* Hash table for the invariants. */
-static htab_t invariant_table;
-
-/* Hash function for INVARIANT. */
-static hashval_t
-invariant_hash (const void *invariant)
-{
- rtx inv = ((const_invariant_ptr_t) invariant)->invariant_rtx;
- return lra_rtx_hash (inv);
-}
-
-/* Equal function for invariants INVARIANT1 and INVARIANT2. */
-static int
-invariant_eq_p (const void *invariant1, const void *invariant2)
-{
- rtx inv1 = ((const_invariant_ptr_t) invariant1)->invariant_rtx;
- rtx inv2 = ((const_invariant_ptr_t) invariant2)->invariant_rtx;
-
- return rtx_equal_p (inv1, inv2);
-}
-
-/* Insert INVARIANT_RTX into the table if it is not there yet. Return
- invariant which is in the table. */
-static invariant_ptr_t
-insert_invariant (rtx invariant_rtx)
-{
- void **entry_ptr;
- invariant_t invariant;
- invariant_ptr_t invariant_ptr;
-
- invariant.invariant_rtx = invariant_rtx;
- entry_ptr = htab_find_slot (invariant_table, &invariant, INSERT);
- if (*entry_ptr == NULL)
- {
- invariant_ptr = invariants_pool->allocate ();
- invariant_ptr->invariant_rtx = invariant_rtx;
- invariant_ptr->insn = NULL;
- invariants.safe_push (invariant_ptr);
- *entry_ptr = (void *) invariant_ptr;
- }
- return (invariant_ptr_t) *entry_ptr;
-}
-
-/* Initiate the invariant table. */
-static void
-initiate_invariants (void)
-{
- invariants.create (100);
- invariants_pool
- = new object_allocator<lra_invariant> ("Inheritance invariants");
- invariant_table = htab_create (100, invariant_hash, invariant_eq_p, NULL);
-}
-
-/* Finish the invariant table. */
-static void
-finish_invariants (void)
-{
- htab_delete (invariant_table);
- delete invariants_pool;
- invariants.release ();
-}
-
-/* Make the invariant table empty. */
-static void
-clear_invariants (void)
-{
- htab_empty (invariant_table);
- invariants_pool->release ();
- invariants.truncate (0);
-}
-
-
-
-/* This page contains code to do inheritance/split
- transformations. */
-
-/* Number of reloads passed so far in current EBB. */
-static int reloads_num;
-
-/* Number of calls passed so far in current EBB. */
-static int calls_num;
-
-/* Index ID is the CALLS_NUM associated the last call we saw with
- ABI identifier ID. */
-static int last_call_for_abi[NUM_ABI_IDS];
-
-/* Which registers have been fully or partially clobbered by a call
- since they were last used. */
-static HARD_REG_SET full_and_partial_call_clobbers;
-
-/* Current reload pseudo check for validity of elements in
- USAGE_INSNS. */
-static int curr_usage_insns_check;
-
-/* Info about last usage of registers in EBB to do inheritance/split
- transformation. Inheritance transformation is done from a spilled
- pseudo and split transformations from a hard register or a pseudo
- assigned to a hard register. */
-struct usage_insns
-{
- /* If the value is equal to CURR_USAGE_INSNS_CHECK, then the member
- value INSNS is valid. The insns is chain of optional debug insns
- and a finishing non-debug insn using the corresponding reg. The
- value is also used to mark the registers which are set up in the
- current insn. The negated insn uid is used for this. */
- int check;
- /* Value of global reloads_num at the last insn in INSNS. */
- int reloads_num;
- /* Value of global reloads_nums at the last insn in INSNS. */
- int calls_num;
- /* It can be true only for splitting. And it means that the restore
- insn should be put after insn given by the following member. */
- bool after_p;
- /* Next insns in the current EBB which use the original reg and the
- original reg value is not changed between the current insn and
- the next insns. In order words, e.g. for inheritance, if we need
- to use the original reg value again in the next insns we can try
- to use the value in a hard register from a reload insn of the
- current insn. */
- rtx insns;
-};
-
-/* Map: regno -> corresponding pseudo usage insns. */
-static struct usage_insns *usage_insns;
-
-static void
-setup_next_usage_insn (int regno, rtx insn, int reloads_num, bool after_p)
-{
- usage_insns[regno].check = curr_usage_insns_check;
- usage_insns[regno].insns = insn;
- usage_insns[regno].reloads_num = reloads_num;
- usage_insns[regno].calls_num = calls_num;
- usage_insns[regno].after_p = after_p;
- if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
- remove_from_hard_reg_set (&full_and_partial_call_clobbers,
- PSEUDO_REGNO_MODE (regno),
- reg_renumber[regno]);
-}
-
-/* The function is used to form list REGNO usages which consists of
- optional debug insns finished by a non-debug insn using REGNO.
- RELOADS_NUM is current number of reload insns processed so far. */
-static void
-add_next_usage_insn (int regno, rtx_insn *insn, int reloads_num)
-{
- rtx next_usage_insns;
-
- if (usage_insns[regno].check == curr_usage_insns_check
- && (next_usage_insns = usage_insns[regno].insns) != NULL_RTX
- && DEBUG_INSN_P (insn))
- {
- /* Check that we did not add the debug insn yet. */
- if (next_usage_insns != insn
- && (GET_CODE (next_usage_insns) != INSN_LIST
- || XEXP (next_usage_insns, 0) != insn))
- usage_insns[regno].insns = gen_rtx_INSN_LIST (VOIDmode, insn,
- next_usage_insns);
- }
- else if (NONDEBUG_INSN_P (insn))
- setup_next_usage_insn (regno, insn, reloads_num, false);
- else
- usage_insns[regno].check = 0;
-}
-
-/* Return first non-debug insn in list USAGE_INSNS. */
-static rtx_insn *
-skip_usage_debug_insns (rtx usage_insns)
-{
- rtx insn;
-
- /* Skip debug insns. */
- for (insn = usage_insns;
- insn != NULL_RTX && GET_CODE (insn) == INSN_LIST;
- insn = XEXP (insn, 1))
- ;
- return safe_as_a <rtx_insn *> (insn);
-}
-
-/* Return true if we need secondary memory moves for insn in
- USAGE_INSNS after inserting inherited pseudo of class INHER_CL
- into the insn. */
-static bool
-check_secondary_memory_needed_p (enum reg_class inher_cl ATTRIBUTE_UNUSED,
- rtx usage_insns ATTRIBUTE_UNUSED)
-{
- rtx_insn *insn;
- rtx set, dest;
- enum reg_class cl;
-
- if (inher_cl == ALL_REGS
- || (insn = skip_usage_debug_insns (usage_insns)) == NULL_RTX)
- return false;
- lra_assert (INSN_P (insn));
- if ((set = single_set (insn)) == NULL_RTX || ! REG_P (SET_DEST (set)))
- return false;
- dest = SET_DEST (set);
- if (! REG_P (dest))
- return false;
- lra_assert (inher_cl != NO_REGS);
- cl = get_reg_class (REGNO (dest));
- return (cl != NO_REGS && cl != ALL_REGS
- && targetm.secondary_memory_needed (GET_MODE (dest), inher_cl, cl));
-}
-
-/* Registers involved in inheritance/split in the current EBB
- (inheritance/split pseudos and original registers). */
-static bitmap_head check_only_regs;
-
-/* Reload pseudos cannot be involded in invariant inheritance in the
- current EBB. */
-static bitmap_head invalid_invariant_regs;
-
-/* Do inheritance transformations for insn INSN, which defines (if
- DEF_P) or uses ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which
- instruction in the EBB next uses ORIGINAL_REGNO; it has the same
- form as the "insns" field of usage_insns. Return true if we
- succeed in such transformation.
-
- The transformations look like:
-
- p <- ... i <- ...
- ... p <- i (new insn)
- ... =>
- <- ... p ... <- ... i ...
- or
- ... i <- p (new insn)
- <- ... p ... <- ... i ...
- ... =>
- <- ... p ... <- ... i ...
- where p is a spilled original pseudo and i is a new inheritance pseudo.
-
-
- The inheritance pseudo has the smallest class of two classes CL and
- class of ORIGINAL REGNO. */
-static bool
-inherit_reload_reg (bool def_p, int original_regno,
- enum reg_class cl, rtx_insn *insn, rtx next_usage_insns)
-{
- if (optimize_function_for_size_p (cfun))
- return false;
-
- enum reg_class rclass = lra_get_allocno_class (original_regno);
- rtx original_reg = regno_reg_rtx[original_regno];
- rtx new_reg, usage_insn;
- rtx_insn *new_insns;
-
- lra_assert (! usage_insns[original_regno].after_p);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
- if (! ira_reg_classes_intersect_p[cl][rclass])
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Rejecting inheritance for %d "
- "because of disjoint classes %s and %s\n",
- original_regno, reg_class_names[cl],
- reg_class_names[rclass]);
- fprintf (lra_dump_file,
- " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- }
- return false;
- }
- if ((ira_class_subset_p[cl][rclass] && cl != rclass)
- /* We don't use a subset of two classes because it can be
- NO_REGS. This transformation is still profitable in most
- cases even if the classes are not intersected as register
- move is probably cheaper than a memory load. */
- || ira_class_hard_regs_num[cl] < ira_class_hard_regs_num[rclass])
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Use smallest class of %s and %s\n",
- reg_class_names[cl], reg_class_names[rclass]);
-
- rclass = cl;
- }
- if (check_secondary_memory_needed_p (rclass, next_usage_insns))
- {
- /* Reject inheritance resulting in secondary memory moves.
- Otherwise, there is a danger in LRA cycling. Also such
- transformation will be unprofitable. */
- if (lra_dump_file != NULL)
- {
- rtx_insn *insn = skip_usage_debug_insns (next_usage_insns);
- rtx set = single_set (insn);
-
- lra_assert (set != NULL_RTX);
-
- rtx dest = SET_DEST (set);
-
- lra_assert (REG_P (dest));
- fprintf (lra_dump_file,
- " Rejecting inheritance for insn %d(%s)<-%d(%s) "
- "as secondary mem is needed\n",
- REGNO (dest), reg_class_names[get_reg_class (REGNO (dest))],
- original_regno, reg_class_names[rclass]);
- fprintf (lra_dump_file,
- " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- }
- return false;
- }
- new_reg = lra_create_new_reg (GET_MODE (original_reg), original_reg,
- rclass, "inheritance");
- start_sequence ();
- if (def_p)
- lra_emit_move (original_reg, new_reg);
- else
- lra_emit_move (new_reg, original_reg);
- new_insns = get_insns ();
- end_sequence ();
- if (NEXT_INSN (new_insns) != NULL_RTX)
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Rejecting inheritance %d->%d "
- "as it results in 2 or more insns:\n",
- original_regno, REGNO (new_reg));
- dump_rtl_slim (lra_dump_file, new_insns, NULL, -1, 0);
- fprintf (lra_dump_file,
- " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- }
- return false;
- }
- lra_substitute_pseudo_within_insn (insn, original_regno, new_reg, false);
- lra_update_insn_regno_info (insn);
- if (! def_p)
- /* We now have a new usage insn for original regno. */
- setup_next_usage_insn (original_regno, new_insns, reloads_num, false);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Original reg change %d->%d (bb%d):\n",
- original_regno, REGNO (new_reg), BLOCK_FOR_INSN (insn)->index);
- lra_reg_info[REGNO (new_reg)].restore_rtx = regno_reg_rtx[original_regno];
- bitmap_set_bit (&check_only_regs, REGNO (new_reg));
- bitmap_set_bit (&check_only_regs, original_regno);
- bitmap_set_bit (&lra_inheritance_pseudos, REGNO (new_reg));
- if (def_p)
- lra_process_new_insns (insn, NULL, new_insns,
- "Add original<-inheritance");
- else
- lra_process_new_insns (insn, new_insns, NULL,
- "Add inheritance<-original");
- while (next_usage_insns != NULL_RTX)
- {
- if (GET_CODE (next_usage_insns) != INSN_LIST)
- {
- usage_insn = next_usage_insns;
- lra_assert (NONDEBUG_INSN_P (usage_insn));
- next_usage_insns = NULL;
- }
- else
- {
- usage_insn = XEXP (next_usage_insns, 0);
- lra_assert (DEBUG_INSN_P (usage_insn));
- next_usage_insns = XEXP (next_usage_insns, 1);
- }
- lra_substitute_pseudo (&usage_insn, original_regno, new_reg, false,
- DEBUG_INSN_P (usage_insn));
- lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
- if (lra_dump_file != NULL)
- {
- basic_block bb = BLOCK_FOR_INSN (usage_insn);
- fprintf (lra_dump_file,
- " Inheritance reuse change %d->%d (bb%d):\n",
- original_regno, REGNO (new_reg),
- bb ? bb->index : -1);
- dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
- }
- }
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- return true;
-}
-
-/* Return true if we need a caller save/restore for pseudo REGNO which
- was assigned to a hard register. */
-static inline bool
-need_for_call_save_p (int regno)
-{
- lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0);
- if (usage_insns[regno].calls_num < calls_num)
- {
- unsigned int abis = 0;
- for (unsigned int i = 0; i < NUM_ABI_IDS; ++i)
- if (last_call_for_abi[i] > usage_insns[regno].calls_num)
- abis |= 1 << i;
- gcc_assert (abis);
- if (call_clobbered_in_region_p (abis, full_and_partial_call_clobbers,
- PSEUDO_REGNO_MODE (regno),
- reg_renumber[regno]))
- return true;
- }
- return false;
-}
-
-/* Global registers occurring in the current EBB. */
-static bitmap_head ebb_global_regs;
-
-/* Return true if we need a split for hard register REGNO or pseudo
- REGNO which was assigned to a hard register.
- POTENTIAL_RELOAD_HARD_REGS contains hard registers which might be
- used for reloads since the EBB end. It is an approximation of the
- used hard registers in the split range. The exact value would
- require expensive calculations. If we were aggressive with
- splitting because of the approximation, the split pseudo will save
- the same hard register assignment and will be removed in the undo
- pass. We still need the approximation because too aggressive
- splitting would result in too inaccurate cost calculation in the
- assignment pass because of too many generated moves which will be
- probably removed in the undo pass. */
-static inline bool
-need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int regno)
-{
- int hard_regno = regno < FIRST_PSEUDO_REGISTER ? regno : reg_renumber[regno];
-
- lra_assert (hard_regno >= 0);
- return ((TEST_HARD_REG_BIT (potential_reload_hard_regs, hard_regno)
- /* Don't split eliminable hard registers, otherwise we can
- split hard registers like hard frame pointer, which
- lives on BB start/end according to DF-infrastructure,
- when there is a pseudo assigned to the register and
- living in the same BB. */
- && (regno >= FIRST_PSEUDO_REGISTER
- || ! TEST_HARD_REG_BIT (eliminable_regset, hard_regno))
- && ! TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno)
- /* Don't split call clobbered hard regs living through
- calls, otherwise we might have a check problem in the
- assign sub-pass as in the most cases (exception is a
- situation when check_and_force_assignment_correctness_p value is
- true) the assign pass assumes that all pseudos living
- through calls are assigned to call saved hard regs. */
- && (regno >= FIRST_PSEUDO_REGISTER
- || !TEST_HARD_REG_BIT (full_and_partial_call_clobbers, regno))
- /* We need at least 2 reloads to make pseudo splitting
- profitable. We should provide hard regno splitting in
- any case to solve 1st insn scheduling problem when
- moving hard register definition up might result in
- impossibility to find hard register for reload pseudo of
- small register class. */
- && (usage_insns[regno].reloads_num
- + (regno < FIRST_PSEUDO_REGISTER ? 0 : 3) < reloads_num)
- && (regno < FIRST_PSEUDO_REGISTER
- /* For short living pseudos, spilling + inheritance can
- be considered a substitution for splitting.
- Therefore we do not splitting for local pseudos. It
- decreases also aggressiveness of splitting. The
- minimal number of references is chosen taking into
- account that for 2 references splitting has no sense
- as we can just spill the pseudo. */
- || (regno >= FIRST_PSEUDO_REGISTER
- && lra_reg_info[regno].nrefs > 3
- && bitmap_bit_p (&ebb_global_regs, regno))))
- || (regno >= FIRST_PSEUDO_REGISTER && need_for_call_save_p (regno)));
-}
-
-/* Return class for the split pseudo created from original pseudo with
- ALLOCNO_CLASS and MODE which got a hard register HARD_REGNO. We
- choose subclass of ALLOCNO_CLASS which contains HARD_REGNO and
- results in no secondary memory movements. */
-static enum reg_class
-choose_split_class (enum reg_class allocno_class,
- int hard_regno ATTRIBUTE_UNUSED,
- machine_mode mode ATTRIBUTE_UNUSED)
-{
- int i;
- enum reg_class cl, best_cl = NO_REGS;
- enum reg_class hard_reg_class ATTRIBUTE_UNUSED
- = REGNO_REG_CLASS (hard_regno);
-
- if (! targetm.secondary_memory_needed (mode, allocno_class, allocno_class)
- && TEST_HARD_REG_BIT (reg_class_contents[allocno_class], hard_regno))
- return allocno_class;
- for (i = 0;
- (cl = reg_class_subclasses[allocno_class][i]) != LIM_REG_CLASSES;
- i++)
- if (! targetm.secondary_memory_needed (mode, cl, hard_reg_class)
- && ! targetm.secondary_memory_needed (mode, hard_reg_class, cl)
- && TEST_HARD_REG_BIT (reg_class_contents[cl], hard_regno)
- && (best_cl == NO_REGS
- || ira_class_hard_regs_num[best_cl] < ira_class_hard_regs_num[cl]))
- best_cl = cl;
- return best_cl;
-}
-
-/* Copy any equivalence information from ORIGINAL_REGNO to NEW_REGNO.
- It only makes sense to call this function if NEW_REGNO is always
- equal to ORIGINAL_REGNO. */
-
-static void
-lra_copy_reg_equiv (unsigned int new_regno, unsigned int original_regno)
-{
- if (!ira_reg_equiv[original_regno].defined_p)
- return;
-
- ira_expand_reg_equiv ();
- ira_reg_equiv[new_regno].defined_p = true;
- if (ira_reg_equiv[original_regno].memory)
- ira_reg_equiv[new_regno].memory
- = copy_rtx (ira_reg_equiv[original_regno].memory);
- if (ira_reg_equiv[original_regno].constant)
- ira_reg_equiv[new_regno].constant
- = copy_rtx (ira_reg_equiv[original_regno].constant);
- if (ira_reg_equiv[original_regno].invariant)
- ira_reg_equiv[new_regno].invariant
- = copy_rtx (ira_reg_equiv[original_regno].invariant);
-}
-
-/* Do split transformations for insn INSN, which defines or uses
- ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which instruction in
- the EBB next uses ORIGINAL_REGNO; it has the same form as the
- "insns" field of usage_insns. If TO is not NULL, we don't use
- usage_insns, we put restore insns after TO insn. It is a case when
- we call it from lra_split_hard_reg_for, outside the inheritance
- pass.
-
- The transformations look like:
-
- p <- ... p <- ...
- ... s <- p (new insn -- save)
- ... =>
- ... p <- s (new insn -- restore)
- <- ... p ... <- ... p ...
- or
- <- ... p ... <- ... p ...
- ... s <- p (new insn -- save)
- ... =>
- ... p <- s (new insn -- restore)
- <- ... p ... <- ... p ...
-
- where p is an original pseudo got a hard register or a hard
- register and s is a new split pseudo. The save is put before INSN
- if BEFORE_P is true. Return true if we succeed in such
- transformation. */
-static bool
-split_reg (bool before_p, int original_regno, rtx_insn *insn,
- rtx next_usage_insns, rtx_insn *to)
-{
- enum reg_class rclass;
- rtx original_reg;
- int hard_regno, nregs;
- rtx new_reg, usage_insn;
- rtx_insn *restore, *save;
- bool after_p;
- bool call_save_p;
- machine_mode mode;
-
- if (original_regno < FIRST_PSEUDO_REGISTER)
- {
- rclass = ira_allocno_class_translate[REGNO_REG_CLASS (original_regno)];
- hard_regno = original_regno;
- call_save_p = false;
- nregs = 1;
- mode = lra_reg_info[hard_regno].biggest_mode;
- machine_mode reg_rtx_mode = GET_MODE (regno_reg_rtx[hard_regno]);
- /* A reg can have a biggest_mode of VOIDmode if it was only ever seen as
- part of a multi-word register. In that case, just use the reg_rtx
- mode. Do the same also if the biggest mode was larger than a register
- or we can not compare the modes. Otherwise, limit the size to that of
- the biggest access in the function or to the natural mode at least. */
- if (mode == VOIDmode
- || !ordered_p (GET_MODE_PRECISION (mode),
- GET_MODE_PRECISION (reg_rtx_mode))
- || paradoxical_subreg_p (mode, reg_rtx_mode)
- || maybe_gt (GET_MODE_PRECISION (reg_rtx_mode), GET_MODE_PRECISION (mode)))
- {
- original_reg = regno_reg_rtx[hard_regno];
- mode = reg_rtx_mode;
- }
- else
- original_reg = gen_rtx_REG (mode, hard_regno);
- }
- else
- {
- mode = PSEUDO_REGNO_MODE (original_regno);
- hard_regno = reg_renumber[original_regno];
- nregs = hard_regno_nregs (hard_regno, mode);
- rclass = lra_get_allocno_class (original_regno);
- original_reg = regno_reg_rtx[original_regno];
- call_save_p = need_for_call_save_p (original_regno);
- }
- lra_assert (hard_regno >= 0);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " ((((((((((((((((((((((((((((((((((((((((((((((((\n");
-
- if (call_save_p)
- {
- mode = HARD_REGNO_CALLER_SAVE_MODE (hard_regno,
- hard_regno_nregs (hard_regno, mode),
- mode);
- new_reg = lra_create_new_reg (mode, NULL_RTX, NO_REGS, "save");
- }
- else
- {
- rclass = choose_split_class (rclass, hard_regno, mode);
- if (rclass == NO_REGS)
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Rejecting split of %d(%s): "
- "no good reg class for %d(%s)\n",
- original_regno,
- reg_class_names[lra_get_allocno_class (original_regno)],
- hard_regno,
- reg_class_names[REGNO_REG_CLASS (hard_regno)]);
- fprintf
- (lra_dump_file,
- " ))))))))))))))))))))))))))))))))))))))))))))))))\n");
- }
- return false;
- }
- /* Split_if_necessary can split hard registers used as part of a
- multi-register mode but splits each register individually. The
- mode used for each independent register may not be supported
- so reject the split. Splitting the wider mode should theoretically
- be possible but is not implemented. */
- if (!targetm.hard_regno_mode_ok (hard_regno, mode))
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Rejecting split of %d(%s): unsuitable mode %s\n",
- original_regno,
- reg_class_names[lra_get_allocno_class (original_regno)],
- GET_MODE_NAME (mode));
- fprintf
- (lra_dump_file,
- " ))))))))))))))))))))))))))))))))))))))))))))))))\n");
- }
- return false;
- }
- new_reg = lra_create_new_reg (mode, original_reg, rclass, "split");
- reg_renumber[REGNO (new_reg)] = hard_regno;
- }
- int new_regno = REGNO (new_reg);
- save = emit_spill_move (true, new_reg, original_reg);
- if (NEXT_INSN (save) != NULL_RTX && !call_save_p)
- {
- if (lra_dump_file != NULL)
- {
- fprintf
- (lra_dump_file,
- " Rejecting split %d->%d resulting in > 2 save insns:\n",
- original_regno, new_regno);
- dump_rtl_slim (lra_dump_file, save, NULL, -1, 0);
- fprintf (lra_dump_file,
- " ))))))))))))))))))))))))))))))))))))))))))))))))\n");
- }
- return false;
- }
- restore = emit_spill_move (false, new_reg, original_reg);
- if (NEXT_INSN (restore) != NULL_RTX && !call_save_p)
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Rejecting split %d->%d "
- "resulting in > 2 restore insns:\n",
- original_regno, new_regno);
- dump_rtl_slim (lra_dump_file, restore, NULL, -1, 0);
- fprintf (lra_dump_file,
- " ))))))))))))))))))))))))))))))))))))))))))))))))\n");
- }
- return false;
- }
- /* Transfer equivalence information to the spill register, so that
- if we fail to allocate the spill register, we have the option of
- rematerializing the original value instead of spilling to the stack. */
- if (!HARD_REGISTER_NUM_P (original_regno)
- && mode == PSEUDO_REGNO_MODE (original_regno))
- lra_copy_reg_equiv (new_regno, original_regno);
- lra_reg_info[new_regno].restore_rtx = regno_reg_rtx[original_regno];
- bitmap_set_bit (&lra_split_regs, new_regno);
- if (to != NULL)
- {
- lra_assert (next_usage_insns == NULL);
- usage_insn = to;
- after_p = TRUE;
- }
- else
- {
- /* We need check_only_regs only inside the inheritance pass. */
- bitmap_set_bit (&check_only_regs, new_regno);
- bitmap_set_bit (&check_only_regs, original_regno);
- after_p = usage_insns[original_regno].after_p;
- for (;;)
- {
- if (GET_CODE (next_usage_insns) != INSN_LIST)
- {
- usage_insn = next_usage_insns;
- break;
- }
- usage_insn = XEXP (next_usage_insns, 0);
- lra_assert (DEBUG_INSN_P (usage_insn));
- next_usage_insns = XEXP (next_usage_insns, 1);
- lra_substitute_pseudo (&usage_insn, original_regno, new_reg, false,
- true);
- lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Split reuse change %d->%d:\n",
- original_regno, new_regno);
- dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
- }
- }
- }
- lra_assert (NOTE_P (usage_insn) || NONDEBUG_INSN_P (usage_insn));
- lra_assert (usage_insn != insn || (after_p && before_p));
- lra_process_new_insns (as_a <rtx_insn *> (usage_insn),
- after_p ? NULL : restore,
- after_p ? restore : NULL,
- call_save_p
- ? "Add reg<-save" : "Add reg<-split");
- lra_process_new_insns (insn, before_p ? save : NULL,
- before_p ? NULL : save,
- call_save_p
- ? "Add save<-reg" : "Add split<-reg");
- if (nregs > 1)
- /* If we are trying to split multi-register. We should check
- conflicts on the next assignment sub-pass. IRA can allocate on
- sub-register levels, LRA do this on pseudos level right now and
- this discrepancy may create allocation conflicts after
- splitting. */
- check_and_force_assignment_correctness_p = true;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " ))))))))))))))))))))))))))))))))))))))))))))))))\n");
- return true;
-}
-
-/* Split a hard reg for reload pseudo REGNO having RCLASS and living
- in the range [FROM, TO]. Return true if did a split. Otherwise,
- return false. */
-bool
-spill_hard_reg_in_range (int regno, enum reg_class rclass, rtx_insn *from, rtx_insn *to)
-{
- int i, hard_regno;
- int rclass_size;
- rtx_insn *insn;
- unsigned int uid;
- bitmap_iterator bi;
- HARD_REG_SET ignore;
-
- lra_assert (from != NULL && to != NULL);
- CLEAR_HARD_REG_SET (ignore);
- EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
- {
- lra_insn_recog_data_t id = lra_insn_recog_data[uid];
- struct lra_static_insn_data *static_id = id->insn_static_data;
- struct lra_insn_reg *reg;
-
- for (reg = id->regs; reg != NULL; reg = reg->next)
- if (reg->regno < FIRST_PSEUDO_REGISTER)
- SET_HARD_REG_BIT (ignore, reg->regno);
- for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
- SET_HARD_REG_BIT (ignore, reg->regno);
- }
- rclass_size = ira_class_hard_regs_num[rclass];
- for (i = 0; i < rclass_size; i++)
- {
- hard_regno = ira_class_hard_regs[rclass][i];
- if (! TEST_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, hard_regno)
- || TEST_HARD_REG_BIT (ignore, hard_regno))
- continue;
- for (insn = from; insn != NEXT_INSN (to); insn = NEXT_INSN (insn))
- {
- struct lra_static_insn_data *static_id;
- struct lra_insn_reg *reg;
-
- if (!INSN_P (insn))
- continue;
- if (bitmap_bit_p (&lra_reg_info[hard_regno].insn_bitmap,
- INSN_UID (insn)))
- break;
- static_id = lra_get_insn_recog_data (insn)->insn_static_data;
- for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->regno == hard_regno)
- break;
- if (reg != NULL)
- break;
- }
- if (insn != NEXT_INSN (to))
- continue;
- if (split_reg (TRUE, hard_regno, from, NULL, to))
- return true;
- }
- return false;
-}
-
-/* Recognize that we need a split transformation for insn INSN, which
- defines or uses REGNO in its insn biggest MODE (we use it only if
- REGNO is a hard register). POTENTIAL_RELOAD_HARD_REGS contains
- hard registers which might be used for reloads since the EBB end.
- Put the save before INSN if BEFORE_P is true. MAX_UID is maximla
- uid before starting INSN processing. Return true if we succeed in
- such transformation. */
-static bool
-split_if_necessary (int regno, machine_mode mode,
- HARD_REG_SET potential_reload_hard_regs,
- bool before_p, rtx_insn *insn, int max_uid)
-{
- bool res = false;
- int i, nregs = 1;
- rtx next_usage_insns;
-
- if (regno < FIRST_PSEUDO_REGISTER)
- nregs = hard_regno_nregs (regno, mode);
- for (i = 0; i < nregs; i++)
- if (usage_insns[regno + i].check == curr_usage_insns_check
- && (next_usage_insns = usage_insns[regno + i].insns) != NULL_RTX
- /* To avoid processing the register twice or more. */
- && ((GET_CODE (next_usage_insns) != INSN_LIST
- && INSN_UID (next_usage_insns) < max_uid)
- || (GET_CODE (next_usage_insns) == INSN_LIST
- && (INSN_UID (XEXP (next_usage_insns, 0)) < max_uid)))
- && need_for_split_p (potential_reload_hard_regs, regno + i)
- && split_reg (before_p, regno + i, insn, next_usage_insns, NULL))
- res = true;
- return res;
-}
-
-/* Return TRUE if rtx X is considered as an invariant for
- inheritance. */
-static bool
-invariant_p (const_rtx x)
-{
- machine_mode mode;
- const char *fmt;
- enum rtx_code code;
- int i, j;
-
- if (side_effects_p (x))
- return false;
-
- code = GET_CODE (x);
- mode = GET_MODE (x);
- if (code == SUBREG)
- {
- x = SUBREG_REG (x);
- code = GET_CODE (x);
- mode = wider_subreg_mode (mode, GET_MODE (x));
- }
-
- if (MEM_P (x))
- return false;
-
- if (REG_P (x))
- {
- int i, nregs, regno = REGNO (x);
-
- if (regno >= FIRST_PSEUDO_REGISTER || regno == STACK_POINTER_REGNUM
- || TEST_HARD_REG_BIT (eliminable_regset, regno)
- || GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
- return false;
- nregs = hard_regno_nregs (regno, mode);
- for (i = 0; i < nregs; i++)
- if (! fixed_regs[regno + i]
- /* A hard register may be clobbered in the current insn
- but we can ignore this case because if the hard
- register is used it should be set somewhere after the
- clobber. */
- || bitmap_bit_p (&invalid_invariant_regs, regno + i))
- return false;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (! invariant_p (XEXP (x, i)))
- return false;
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (! invariant_p (XVECEXP (x, i, j)))
- return false;
- }
- }
- return true;
-}
-
-/* We have 'dest_reg <- invariant'. Let us try to make an invariant
- inheritance transformation (using dest_reg instead invariant in a
- subsequent insn). */
-static bool
-process_invariant_for_inheritance (rtx dst_reg, rtx invariant_rtx)
-{
- invariant_ptr_t invariant_ptr;
- rtx_insn *insn, *new_insns;
- rtx insn_set, insn_reg, new_reg;
- int insn_regno;
- bool succ_p = false;
- int dst_regno = REGNO (dst_reg);
- machine_mode dst_mode = GET_MODE (dst_reg);
- enum reg_class cl = lra_get_allocno_class (dst_regno), insn_reg_cl;
-
- invariant_ptr = insert_invariant (invariant_rtx);
- if ((insn = invariant_ptr->insn) != NULL_RTX)
- {
- /* We have a subsequent insn using the invariant. */
- insn_set = single_set (insn);
- lra_assert (insn_set != NULL);
- insn_reg = SET_DEST (insn_set);
- lra_assert (REG_P (insn_reg));
- insn_regno = REGNO (insn_reg);
- insn_reg_cl = lra_get_allocno_class (insn_regno);
-
- if (dst_mode == GET_MODE (insn_reg)
- /* We should consider only result move reg insns which are
- cheap. */
- && targetm.register_move_cost (dst_mode, cl, insn_reg_cl) == 2
- && targetm.register_move_cost (dst_mode, cl, cl) == 2)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n");
- new_reg = lra_create_new_reg (dst_mode, dst_reg,
- cl, "invariant inheritance");
- bitmap_set_bit (&lra_inheritance_pseudos, REGNO (new_reg));
- bitmap_set_bit (&check_only_regs, REGNO (new_reg));
- lra_reg_info[REGNO (new_reg)].restore_rtx = PATTERN (insn);
- start_sequence ();
- lra_emit_move (new_reg, dst_reg);
- new_insns = get_insns ();
- end_sequence ();
- lra_process_new_insns (curr_insn, NULL, new_insns,
- "Add invariant inheritance<-original");
- start_sequence ();
- lra_emit_move (SET_DEST (insn_set), new_reg);
- new_insns = get_insns ();
- end_sequence ();
- lra_process_new_insns (insn, NULL, new_insns,
- "Changing reload<-inheritance");
- lra_set_insn_deleted (insn);
- succ_p = true;
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Invariant inheritance reuse change %d (bb%d):\n",
- REGNO (new_reg), BLOCK_FOR_INSN (insn)->index);
- dump_insn_slim (lra_dump_file, insn);
- fprintf (lra_dump_file,
- " ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\n");
- }
- }
- }
- invariant_ptr->insn = curr_insn;
- return succ_p;
-}
-
-/* Check only registers living at the current program point in the
- current EBB. */
-static bitmap_head live_regs;
-
-/* Update live info in EBB given by its HEAD and TAIL insns after
- inheritance/split transformation. The function removes dead moves
- too. */
-static void
-update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
-{
- unsigned int j;
- int i, regno;
- bool live_p;
- rtx_insn *prev_insn;
- rtx set;
- bool remove_p;
- basic_block last_bb, prev_bb, curr_bb;
- bitmap_iterator bi;
- struct lra_insn_reg *reg;
- edge e;
- edge_iterator ei;
-
- last_bb = BLOCK_FOR_INSN (tail);
- prev_bb = NULL;
- for (curr_insn = tail;
- curr_insn != PREV_INSN (head);
- curr_insn = prev_insn)
- {
- prev_insn = PREV_INSN (curr_insn);
- /* We need to process empty blocks too. They contain
- NOTE_INSN_BASIC_BLOCK referring for the basic block. */
- if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
- continue;
- curr_bb = BLOCK_FOR_INSN (curr_insn);
- if (curr_bb != prev_bb)
- {
- if (prev_bb != NULL)
- {
- /* Update df_get_live_in (prev_bb): */
- EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi)
- if (bitmap_bit_p (&live_regs, j))
- bitmap_set_bit (df_get_live_in (prev_bb), j);
- else
- bitmap_clear_bit (df_get_live_in (prev_bb), j);
- }
- if (curr_bb != last_bb)
- {
- /* Update df_get_live_out (curr_bb): */
- EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi)
- {
- live_p = bitmap_bit_p (&live_regs, j);
- if (! live_p)
- FOR_EACH_EDGE (e, ei, curr_bb->succs)
- if (bitmap_bit_p (df_get_live_in (e->dest), j))
- {
- live_p = true;
- break;
- }
- if (live_p)
- bitmap_set_bit (df_get_live_out (curr_bb), j);
- else
- bitmap_clear_bit (df_get_live_out (curr_bb), j);
- }
- }
- prev_bb = curr_bb;
- bitmap_and (&live_regs, &check_only_regs, df_get_live_out (curr_bb));
- }
- if (! NONDEBUG_INSN_P (curr_insn))
- continue;
- curr_id = lra_get_insn_recog_data (curr_insn);
- curr_static_id = curr_id->insn_static_data;
- remove_p = false;
- if ((set = single_set (curr_insn)) != NULL_RTX
- && REG_P (SET_DEST (set))
- && (regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER
- && SET_DEST (set) != pic_offset_table_rtx
- && bitmap_bit_p (&check_only_regs, regno)
- && ! bitmap_bit_p (&live_regs, regno))
- remove_p = true;
- /* See which defined values die here. */
- for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && ! reg->subreg_p)
- bitmap_clear_bit (&live_regs, reg->regno);
- for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && ! reg->subreg_p)
- bitmap_clear_bit (&live_regs, reg->regno);
- if (curr_id->arg_hard_regs != NULL)
- /* Make clobbered argument hard registers die. */
- for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (regno >= FIRST_PSEUDO_REGISTER)
- bitmap_clear_bit (&live_regs, regno - FIRST_PSEUDO_REGISTER);
- /* Mark each used value as live. */
- for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_OUT
- && bitmap_bit_p (&check_only_regs, reg->regno))
- bitmap_set_bit (&live_regs, reg->regno);
- for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_OUT
- && bitmap_bit_p (&check_only_regs, reg->regno))
- bitmap_set_bit (&live_regs, reg->regno);
- if (curr_id->arg_hard_regs != NULL)
- /* Make used argument hard registers live. */
- for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (regno < FIRST_PSEUDO_REGISTER
- && bitmap_bit_p (&check_only_regs, regno))
- bitmap_set_bit (&live_regs, regno);
- /* It is quite important to remove dead move insns because it
- means removing dead store. We don't need to process them for
- constraints. */
- if (remove_p)
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Removing dead insn:\n ");
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- lra_set_insn_deleted (curr_insn);
- }
- }
-}
-
-/* The structure describes info to do an inheritance for the current
- insn. We need to collect such info first before doing the
- transformations because the transformations change the insn
- internal representation. */
-struct to_inherit
-{
- /* Original regno. */
- int regno;
- /* Subsequent insns which can inherit original reg value. */
- rtx insns;
-};
-
-/* Array containing all info for doing inheritance from the current
- insn. */
-static struct to_inherit to_inherit[LRA_MAX_INSN_RELOADS];
-
-/* Number elements in the previous array. */
-static int to_inherit_num;
-
-/* Add inheritance info REGNO and INSNS. Their meaning is described in
- structure to_inherit. */
-static void
-add_to_inherit (int regno, rtx insns)
-{
- int i;
-
- for (i = 0; i < to_inherit_num; i++)
- if (to_inherit[i].regno == regno)
- return;
- lra_assert (to_inherit_num < LRA_MAX_INSN_RELOADS);
- to_inherit[to_inherit_num].regno = regno;
- to_inherit[to_inherit_num++].insns = insns;
-}
-
-/* Return the last non-debug insn in basic block BB, or the block begin
- note if none. */
-static rtx_insn *
-get_last_insertion_point (basic_block bb)
-{
- rtx_insn *insn;
-
- FOR_BB_INSNS_REVERSE (bb, insn)
- if (NONDEBUG_INSN_P (insn) || NOTE_INSN_BASIC_BLOCK_P (insn))
- return insn;
- gcc_unreachable ();
-}
-
-/* Set up RES by registers living on edges FROM except the edge (FROM,
- TO) or by registers set up in a jump insn in BB FROM. */
-static void
-get_live_on_other_edges (basic_block from, basic_block to, bitmap res)
-{
- rtx_insn *last;
- struct lra_insn_reg *reg;
- edge e;
- edge_iterator ei;
-
- lra_assert (to != NULL);
- bitmap_clear (res);
- FOR_EACH_EDGE (e, ei, from->succs)
- if (e->dest != to)
- bitmap_ior_into (res, df_get_live_in (e->dest));
- last = get_last_insertion_point (from);
- if (! JUMP_P (last))
- return;
- curr_id = lra_get_insn_recog_data (last);
- for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_IN)
- bitmap_set_bit (res, reg->regno);
-}
-
-/* Used as a temporary results of some bitmap calculations. */
-static bitmap_head temp_bitmap;
-
-/* We split for reloads of small class of hard regs. The following
- defines how many hard regs the class should have to be qualified as
- small. The code is mostly oriented to x86/x86-64 architecture
- where some insns need to use only specific register or pair of
- registers and these register can live in RTL explicitly, e.g. for
- parameter passing. */
-static const int max_small_class_regs_num = 2;
-
-/* Do inheritance/split transformations in EBB starting with HEAD and
- finishing on TAIL. We process EBB insns in the reverse order.
- Return true if we did any inheritance/split transformation in the
- EBB.
-
- We should avoid excessive splitting which results in worse code
- because of inaccurate cost calculations for spilling new split
- pseudos in such case. To achieve this we do splitting only if
- register pressure is high in given basic block and there are reload
- pseudos requiring hard registers. We could do more register
- pressure calculations at any given program point to avoid necessary
- splitting even more but it is to expensive and the current approach
- works well enough. */
-static bool
-inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
-{
- int i, src_regno, dst_regno, nregs;
- bool change_p, succ_p, update_reloads_num_p;
- rtx_insn *prev_insn, *last_insn;
- rtx next_usage_insns, curr_set;
- enum reg_class cl;
- struct lra_insn_reg *reg;
- basic_block last_processed_bb, curr_bb = NULL;
- HARD_REG_SET potential_reload_hard_regs, live_hard_regs;
- bitmap to_process;
- unsigned int j;
- bitmap_iterator bi;
- bool head_p, after_p;
-
- change_p = false;
- curr_usage_insns_check++;
- clear_invariants ();
- reloads_num = calls_num = 0;
- for (unsigned int i = 0; i < NUM_ABI_IDS; ++i)
- last_call_for_abi[i] = 0;
- CLEAR_HARD_REG_SET (full_and_partial_call_clobbers);
- bitmap_clear (&check_only_regs);
- bitmap_clear (&invalid_invariant_regs);
- last_processed_bb = NULL;
- CLEAR_HARD_REG_SET (potential_reload_hard_regs);
- live_hard_regs = eliminable_regset | lra_no_alloc_regs;
- /* We don't process new insns generated in the loop. */
- for (curr_insn = tail; curr_insn != PREV_INSN (head); curr_insn = prev_insn)
- {
- prev_insn = PREV_INSN (curr_insn);
- if (BLOCK_FOR_INSN (curr_insn) != NULL)
- curr_bb = BLOCK_FOR_INSN (curr_insn);
- if (last_processed_bb != curr_bb)
- {
- /* We are at the end of BB. Add qualified living
- pseudos for potential splitting. */
- to_process = df_get_live_out (curr_bb);
- if (last_processed_bb != NULL)
- {
- /* We are somewhere in the middle of EBB. */
- get_live_on_other_edges (curr_bb, last_processed_bb,
- &temp_bitmap);
- to_process = &temp_bitmap;
- }
- last_processed_bb = curr_bb;
- last_insn = get_last_insertion_point (curr_bb);
- after_p = (! JUMP_P (last_insn)
- && (! CALL_P (last_insn)
- || (find_reg_note (last_insn,
- REG_NORETURN, NULL_RTX) == NULL_RTX
- && ! SIBLING_CALL_P (last_insn))));
- CLEAR_HARD_REG_SET (potential_reload_hard_regs);
- EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi)
- {
- if ((int) j >= lra_constraint_new_regno_start)
- break;
- if (j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0)
- {
- if (j < FIRST_PSEUDO_REGISTER)
- SET_HARD_REG_BIT (live_hard_regs, j);
- else
- add_to_hard_reg_set (&live_hard_regs,
- PSEUDO_REGNO_MODE (j),
- reg_renumber[j]);
- setup_next_usage_insn (j, last_insn, reloads_num, after_p);
- }
- }
- }
- src_regno = dst_regno = -1;
- curr_set = single_set (curr_insn);
- if (curr_set != NULL_RTX && REG_P (SET_DEST (curr_set)))
- dst_regno = REGNO (SET_DEST (curr_set));
- if (curr_set != NULL_RTX && REG_P (SET_SRC (curr_set)))
- src_regno = REGNO (SET_SRC (curr_set));
- update_reloads_num_p = true;
- if (src_regno < lra_constraint_new_regno_start
- && src_regno >= FIRST_PSEUDO_REGISTER
- && reg_renumber[src_regno] < 0
- && dst_regno >= lra_constraint_new_regno_start
- && (cl = lra_get_allocno_class (dst_regno)) != NO_REGS)
- {
- /* 'reload_pseudo <- original_pseudo'. */
- if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num)
- reloads_num++;
- update_reloads_num_p = false;
- succ_p = false;
- if (usage_insns[src_regno].check == curr_usage_insns_check
- && (next_usage_insns = usage_insns[src_regno].insns) != NULL_RTX)
- succ_p = inherit_reload_reg (false, src_regno, cl,
- curr_insn, next_usage_insns);
- if (succ_p)
- change_p = true;
- else
- setup_next_usage_insn (src_regno, curr_insn, reloads_num, false);
- if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs))
- potential_reload_hard_regs |= reg_class_contents[cl];
- }
- else if (src_regno < 0
- && dst_regno >= lra_constraint_new_regno_start
- && invariant_p (SET_SRC (curr_set))
- && (cl = lra_get_allocno_class (dst_regno)) != NO_REGS
- && ! bitmap_bit_p (&invalid_invariant_regs, dst_regno)
- && ! bitmap_bit_p (&invalid_invariant_regs,
- ORIGINAL_REGNO(regno_reg_rtx[dst_regno])))
- {
- /* 'reload_pseudo <- invariant'. */
- if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num)
- reloads_num++;
- update_reloads_num_p = false;
- if (process_invariant_for_inheritance (SET_DEST (curr_set), SET_SRC (curr_set)))
- change_p = true;
- if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs))
- potential_reload_hard_regs |= reg_class_contents[cl];
- }
- else if (src_regno >= lra_constraint_new_regno_start
- && dst_regno < lra_constraint_new_regno_start
- && dst_regno >= FIRST_PSEUDO_REGISTER
- && reg_renumber[dst_regno] < 0
- && (cl = lra_get_allocno_class (src_regno)) != NO_REGS
- && usage_insns[dst_regno].check == curr_usage_insns_check
- && (next_usage_insns
- = usage_insns[dst_regno].insns) != NULL_RTX)
- {
- if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num)
- reloads_num++;
- update_reloads_num_p = false;
- /* 'original_pseudo <- reload_pseudo'. */
- if (! JUMP_P (curr_insn)
- && inherit_reload_reg (true, dst_regno, cl,
- curr_insn, next_usage_insns))
- change_p = true;
- /* Invalidate. */
- usage_insns[dst_regno].check = 0;
- if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs))
- potential_reload_hard_regs |= reg_class_contents[cl];
- }
- else if (INSN_P (curr_insn))
- {
- int iter;
- int max_uid = get_max_uid ();
-
- curr_id = lra_get_insn_recog_data (curr_insn);
- curr_static_id = curr_id->insn_static_data;
- to_inherit_num = 0;
- /* Process insn definitions. */
- for (iter = 0; iter < 2; iter++)
- for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs;
- reg != NULL;
- reg = reg->next)
- if (reg->type != OP_IN
- && (dst_regno = reg->regno) < lra_constraint_new_regno_start)
- {
- if (dst_regno >= FIRST_PSEUDO_REGISTER && reg->type == OP_OUT
- && reg_renumber[dst_regno] < 0 && ! reg->subreg_p
- && usage_insns[dst_regno].check == curr_usage_insns_check
- && (next_usage_insns
- = usage_insns[dst_regno].insns) != NULL_RTX)
- {
- struct lra_insn_reg *r;
-
- for (r = curr_id->regs; r != NULL; r = r->next)
- if (r->type != OP_OUT && r->regno == dst_regno)
- break;
- /* Don't do inheritance if the pseudo is also
- used in the insn. */
- if (r == NULL)
- /* We cannot do inheritance right now
- because the current insn reg info (chain
- regs) can change after that. */
- add_to_inherit (dst_regno, next_usage_insns);
- }
- /* We cannot process one reg twice here because of
- usage_insns invalidation. */
- if ((dst_regno < FIRST_PSEUDO_REGISTER
- || reg_renumber[dst_regno] >= 0)
- && ! reg->subreg_p && reg->type != OP_IN)
- {
- HARD_REG_SET s;
-
- if (split_if_necessary (dst_regno, reg->biggest_mode,
- potential_reload_hard_regs,
- false, curr_insn, max_uid))
- change_p = true;
- CLEAR_HARD_REG_SET (s);
- if (dst_regno < FIRST_PSEUDO_REGISTER)
- add_to_hard_reg_set (&s, reg->biggest_mode, dst_regno);
- else
- add_to_hard_reg_set (&s, PSEUDO_REGNO_MODE (dst_regno),
- reg_renumber[dst_regno]);
- live_hard_regs &= ~s;
- potential_reload_hard_regs &= ~s;
- }
- /* We should invalidate potential inheritance or
- splitting for the current insn usages to the next
- usage insns (see code below) as the output pseudo
- prevents this. */
- if ((dst_regno >= FIRST_PSEUDO_REGISTER
- && reg_renumber[dst_regno] < 0)
- || (reg->type == OP_OUT && ! reg->subreg_p
- && (dst_regno < FIRST_PSEUDO_REGISTER
- || reg_renumber[dst_regno] >= 0)))
- {
- /* Invalidate and mark definitions. */
- if (dst_regno >= FIRST_PSEUDO_REGISTER)
- usage_insns[dst_regno].check = -(int) INSN_UID (curr_insn);
- else
- {
- nregs = hard_regno_nregs (dst_regno,
- reg->biggest_mode);
- for (i = 0; i < nregs; i++)
- usage_insns[dst_regno + i].check
- = -(int) INSN_UID (curr_insn);
- }
- }
- }
- /* Process clobbered call regs. */
- if (curr_id->arg_hard_regs != NULL)
- for (i = 0; (dst_regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (dst_regno >= FIRST_PSEUDO_REGISTER)
- usage_insns[dst_regno - FIRST_PSEUDO_REGISTER].check
- = -(int) INSN_UID (curr_insn);
- if (! JUMP_P (curr_insn))
- for (i = 0; i < to_inherit_num; i++)
- if (inherit_reload_reg (true, to_inherit[i].regno,
- ALL_REGS, curr_insn,
- to_inherit[i].insns))
- change_p = true;
- if (CALL_P (curr_insn))
- {
- rtx cheap, pat, dest;
- rtx_insn *restore;
- int regno, hard_regno;
-
- calls_num++;
- function_abi callee_abi = insn_callee_abi (curr_insn);
- last_call_for_abi[callee_abi.id ()] = calls_num;
- full_and_partial_call_clobbers
- |= callee_abi.full_and_partial_reg_clobbers ();
- if ((cheap = find_reg_note (curr_insn,
- REG_RETURNED, NULL_RTX)) != NULL_RTX
- && ((cheap = XEXP (cheap, 0)), true)
- && (regno = REGNO (cheap)) >= FIRST_PSEUDO_REGISTER
- && (hard_regno = reg_renumber[regno]) >= 0
- && usage_insns[regno].check == curr_usage_insns_check
- /* If there are pending saves/restores, the
- optimization is not worth. */
- && usage_insns[regno].calls_num == calls_num - 1
- && callee_abi.clobbers_reg_p (GET_MODE (cheap), hard_regno))
- {
- /* Restore the pseudo from the call result as
- REG_RETURNED note says that the pseudo value is
- in the call result and the pseudo is an argument
- of the call. */
- pat = PATTERN (curr_insn);
- if (GET_CODE (pat) == PARALLEL)
- pat = XVECEXP (pat, 0, 0);
- dest = SET_DEST (pat);
- /* For multiple return values dest is PARALLEL.
- Currently we handle only single return value case. */
- if (REG_P (dest))
- {
- start_sequence ();
- emit_move_insn (cheap, copy_rtx (dest));
- restore = get_insns ();
- end_sequence ();
- lra_process_new_insns (curr_insn, NULL, restore,
- "Inserting call parameter restore");
- /* We don't need to save/restore of the pseudo from
- this call. */
- usage_insns[regno].calls_num = calls_num;
- remove_from_hard_reg_set
- (&full_and_partial_call_clobbers,
- GET_MODE (cheap), hard_regno);
- bitmap_set_bit (&check_only_regs, regno);
- }
- }
- }
- to_inherit_num = 0;
- /* Process insn usages. */
- for (iter = 0; iter < 2; iter++)
- for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs;
- reg != NULL;
- reg = reg->next)
- if ((reg->type != OP_OUT
- || (reg->type == OP_OUT && reg->subreg_p))
- && (src_regno = reg->regno) < lra_constraint_new_regno_start)
- {
- if (src_regno >= FIRST_PSEUDO_REGISTER
- && reg_renumber[src_regno] < 0 && reg->type == OP_IN)
- {
- if (usage_insns[src_regno].check == curr_usage_insns_check
- && (next_usage_insns
- = usage_insns[src_regno].insns) != NULL_RTX
- && NONDEBUG_INSN_P (curr_insn))
- add_to_inherit (src_regno, next_usage_insns);
- else if (usage_insns[src_regno].check
- != -(int) INSN_UID (curr_insn))
- /* Add usages but only if the reg is not set up
- in the same insn. */
- add_next_usage_insn (src_regno, curr_insn, reloads_num);
- }
- else if (src_regno < FIRST_PSEUDO_REGISTER
- || reg_renumber[src_regno] >= 0)
- {
- bool before_p;
- rtx_insn *use_insn = curr_insn;
-
- before_p = (JUMP_P (curr_insn)
- || (CALL_P (curr_insn) && reg->type == OP_IN));
- if (NONDEBUG_INSN_P (curr_insn)
- && (! JUMP_P (curr_insn) || reg->type == OP_IN)
- && split_if_necessary (src_regno, reg->biggest_mode,
- potential_reload_hard_regs,
- before_p, curr_insn, max_uid))
- {
- if (reg->subreg_p)
- check_and_force_assignment_correctness_p = true;
- change_p = true;
- /* Invalidate. */
- usage_insns[src_regno].check = 0;
- if (before_p)
- use_insn = PREV_INSN (curr_insn);
- }
- if (NONDEBUG_INSN_P (curr_insn))
- {
- if (src_regno < FIRST_PSEUDO_REGISTER)
- add_to_hard_reg_set (&live_hard_regs,
- reg->biggest_mode, src_regno);
- else
- add_to_hard_reg_set (&live_hard_regs,
- PSEUDO_REGNO_MODE (src_regno),
- reg_renumber[src_regno]);
- }
- if (src_regno >= FIRST_PSEUDO_REGISTER)
- add_next_usage_insn (src_regno, use_insn, reloads_num);
- else
- {
- for (i = 0; i < hard_regno_nregs (src_regno, reg->biggest_mode); i++)
- add_next_usage_insn (src_regno + i, use_insn, reloads_num);
- }
- }
- }
- /* Process used call regs. */
- if (curr_id->arg_hard_regs != NULL)
- for (i = 0; (src_regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (src_regno < FIRST_PSEUDO_REGISTER)
- {
- SET_HARD_REG_BIT (live_hard_regs, src_regno);
- add_next_usage_insn (src_regno, curr_insn, reloads_num);
- }
- for (i = 0; i < to_inherit_num; i++)
- {
- src_regno = to_inherit[i].regno;
- if (inherit_reload_reg (false, src_regno, ALL_REGS,
- curr_insn, to_inherit[i].insns))
- change_p = true;
- else
- setup_next_usage_insn (src_regno, curr_insn, reloads_num, false);
- }
- }
- if (update_reloads_num_p
- && NONDEBUG_INSN_P (curr_insn) && curr_set != NULL_RTX)
- {
- int regno = -1;
- if ((REG_P (SET_DEST (curr_set))
- && (regno = REGNO (SET_DEST (curr_set))) >= lra_constraint_new_regno_start
- && reg_renumber[regno] < 0
- && (cl = lra_get_allocno_class (regno)) != NO_REGS)
- || (REG_P (SET_SRC (curr_set))
- && (regno = REGNO (SET_SRC (curr_set))) >= lra_constraint_new_regno_start
- && reg_renumber[regno] < 0
- && (cl = lra_get_allocno_class (regno)) != NO_REGS))
- {
- if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num)
- reloads_num++;
- if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs))
- potential_reload_hard_regs |= reg_class_contents[cl];
- }
- }
- if (NONDEBUG_INSN_P (curr_insn))
- {
- int regno;
-
- /* Invalidate invariants with changed regs. */
- curr_id = lra_get_insn_recog_data (curr_insn);
- for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_IN)
- {
- bitmap_set_bit (&invalid_invariant_regs, reg->regno);
- bitmap_set_bit (&invalid_invariant_regs,
- ORIGINAL_REGNO (regno_reg_rtx[reg->regno]));
- }
- curr_static_id = curr_id->insn_static_data;
- for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_IN)
- bitmap_set_bit (&invalid_invariant_regs, reg->regno);
- if (curr_id->arg_hard_regs != NULL)
- for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (regno >= FIRST_PSEUDO_REGISTER)
- bitmap_set_bit (&invalid_invariant_regs,
- regno - FIRST_PSEUDO_REGISTER);
- }
- /* We reached the start of the current basic block. */
- if (prev_insn == NULL_RTX || prev_insn == PREV_INSN (head)
- || BLOCK_FOR_INSN (prev_insn) != curr_bb)
- {
- /* We reached the beginning of the current block -- do
- rest of spliting in the current BB. */
- to_process = df_get_live_in (curr_bb);
- if (BLOCK_FOR_INSN (head) != curr_bb)
- {
- /* We are somewhere in the middle of EBB. */
- get_live_on_other_edges (EDGE_PRED (curr_bb, 0)->src,
- curr_bb, &temp_bitmap);
- to_process = &temp_bitmap;
- }
- head_p = true;
- EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi)
- {
- if ((int) j >= lra_constraint_new_regno_start)
- break;
- if (((int) j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0)
- && usage_insns[j].check == curr_usage_insns_check
- && (next_usage_insns = usage_insns[j].insns) != NULL_RTX)
- {
- if (need_for_split_p (potential_reload_hard_regs, j))
- {
- if (lra_dump_file != NULL && head_p)
- {
- fprintf (lra_dump_file,
- " ----------------------------------\n");
- head_p = false;
- }
- if (split_reg (false, j, bb_note (curr_bb),
- next_usage_insns, NULL))
- change_p = true;
- }
- usage_insns[j].check = 0;
- }
- }
- }
- }
- return change_p;
-}
-
-/* This value affects EBB forming. If probability of edge from EBB to
- a BB is not greater than the following value, we don't add the BB
- to EBB. */
-#define EBB_PROBABILITY_CUTOFF \
- ((REG_BR_PROB_BASE * param_lra_inheritance_ebb_probability_cutoff) / 100)
-
-/* Current number of inheritance/split iteration. */
-int lra_inheritance_iter;
-
-/* Entry function for inheritance/split pass. */
-void
-lra_inheritance (void)
-{
- int i;
- basic_block bb, start_bb;
- edge e;
-
- lra_inheritance_iter++;
- if (lra_inheritance_iter > LRA_MAX_INHERITANCE_PASSES)
- return;
- timevar_push (TV_LRA_INHERITANCE);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "\n********** Inheritance #%d: **********\n\n",
- lra_inheritance_iter);
- curr_usage_insns_check = 0;
- usage_insns = XNEWVEC (struct usage_insns, lra_constraint_new_regno_start);
- for (i = 0; i < lra_constraint_new_regno_start; i++)
- usage_insns[i].check = 0;
- bitmap_initialize (&check_only_regs, &reg_obstack);
- bitmap_initialize (&invalid_invariant_regs, &reg_obstack);
- bitmap_initialize (&live_regs, &reg_obstack);
- bitmap_initialize (&temp_bitmap, &reg_obstack);
- bitmap_initialize (&ebb_global_regs, &reg_obstack);
- FOR_EACH_BB_FN (bb, cfun)
- {
- start_bb = bb;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "EBB");
- /* Form a EBB starting with BB. */
- bitmap_clear (&ebb_global_regs);
- bitmap_ior_into (&ebb_global_regs, df_get_live_in (bb));
- for (;;)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " %d", bb->index);
- if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
- || LABEL_P (BB_HEAD (bb->next_bb)))
- break;
- e = find_fallthru_edge (bb->succs);
- if (! e)
- break;
- if (e->probability.initialized_p ()
- && e->probability.to_reg_br_prob_base () < EBB_PROBABILITY_CUTOFF)
- break;
- bb = bb->next_bb;
- }
- bitmap_ior_into (&ebb_global_regs, df_get_live_out (bb));
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "\n");
- if (inherit_in_ebb (BB_HEAD (start_bb), BB_END (bb)))
- /* Remember that the EBB head and tail can change in
- inherit_in_ebb. */
- update_ebb_live_info (BB_HEAD (start_bb), BB_END (bb));
- }
- bitmap_release (&ebb_global_regs);
- bitmap_release (&temp_bitmap);
- bitmap_release (&live_regs);
- bitmap_release (&invalid_invariant_regs);
- bitmap_release (&check_only_regs);
- free (usage_insns);
-
- timevar_pop (TV_LRA_INHERITANCE);
-}
-
-
-
-/* This page contains code to undo failed inheritance/split
- transformations. */
-
-/* Current number of iteration undoing inheritance/split. */
-int lra_undo_inheritance_iter;
-
-/* Fix BB live info LIVE after removing pseudos created on pass doing
- inheritance/split which are REMOVED_PSEUDOS. */
-static void
-fix_bb_live_info (bitmap live, bitmap removed_pseudos)
-{
- unsigned int regno;
- bitmap_iterator bi;
-
- EXECUTE_IF_SET_IN_BITMAP (removed_pseudos, 0, regno, bi)
- if (bitmap_clear_bit (live, regno)
- && REG_P (lra_reg_info[regno].restore_rtx))
- bitmap_set_bit (live, REGNO (lra_reg_info[regno].restore_rtx));
-}
-
-/* Return regno of the (subreg of) REG. Otherwise, return a negative
- number. */
-static int
-get_regno (rtx reg)
-{
- if (GET_CODE (reg) == SUBREG)
- reg = SUBREG_REG (reg);
- if (REG_P (reg))
- return REGNO (reg);
- return -1;
-}
-
-/* Delete a move INSN with destination reg DREGNO and a previous
- clobber insn with the same regno. The inheritance/split code can
- generate moves with preceding clobber and when we delete such moves
- we should delete the clobber insn too to keep the correct life
- info. */
-static void
-delete_move_and_clobber (rtx_insn *insn, int dregno)
-{
- rtx_insn *prev_insn = PREV_INSN (insn);
-
- lra_set_insn_deleted (insn);
- lra_assert (dregno >= 0);
- if (prev_insn != NULL && NONDEBUG_INSN_P (prev_insn)
- && GET_CODE (PATTERN (prev_insn)) == CLOBBER
- && dregno == get_regno (XEXP (PATTERN (prev_insn), 0)))
- lra_set_insn_deleted (prev_insn);
-}
-
-/* Remove inheritance/split pseudos which are in REMOVE_PSEUDOS and
- return true if we did any change. The undo transformations for
- inheritance looks like
- i <- i2
- p <- i => p <- i2
- or removing
- p <- i, i <- p, and i <- i3
- where p is original pseudo from which inheritance pseudo i was
- created, i and i3 are removed inheritance pseudos, i2 is another
- not removed inheritance pseudo. All split pseudos or other
- occurrences of removed inheritance pseudos are changed on the
- corresponding original pseudos.
-
- The function also schedules insns changed and created during
- inheritance/split pass for processing by the subsequent constraint
- pass. */
-static bool
-remove_inheritance_pseudos (bitmap remove_pseudos)
-{
- basic_block bb;
- int regno, sregno, prev_sregno, dregno;
- rtx restore_rtx;
- rtx set, prev_set;
- rtx_insn *prev_insn;
- bool change_p, done_p;
-
- change_p = ! bitmap_empty_p (remove_pseudos);
- /* We cannot finish the function right away if CHANGE_P is true
- because we need to marks insns affected by previous
- inheritance/split pass for processing by the subsequent
- constraint pass. */
- FOR_EACH_BB_FN (bb, cfun)
- {
- fix_bb_live_info (df_get_live_in (bb), remove_pseudos);
- fix_bb_live_info (df_get_live_out (bb), remove_pseudos);
- FOR_BB_INSNS_REVERSE (bb, curr_insn)
- {
- if (! INSN_P (curr_insn))
- continue;
- done_p = false;
- sregno = dregno = -1;
- if (change_p && NONDEBUG_INSN_P (curr_insn)
- && (set = single_set (curr_insn)) != NULL_RTX)
- {
- dregno = get_regno (SET_DEST (set));
- sregno = get_regno (SET_SRC (set));
- }
-
- if (sregno >= 0 && dregno >= 0)
- {
- if (bitmap_bit_p (remove_pseudos, dregno)
- && ! REG_P (lra_reg_info[dregno].restore_rtx))
- {
- /* invariant inheritance pseudo <- original pseudo */
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Removing invariant inheritance:\n");
- dump_insn_slim (lra_dump_file, curr_insn);
- fprintf (lra_dump_file, "\n");
- }
- delete_move_and_clobber (curr_insn, dregno);
- done_p = true;
- }
- else if (bitmap_bit_p (remove_pseudos, sregno)
- && ! REG_P (lra_reg_info[sregno].restore_rtx))
- {
- /* reload pseudo <- invariant inheritance pseudo */
- start_sequence ();
- /* We cannot just change the source. It might be
- an insn different from the move. */
- emit_insn (lra_reg_info[sregno].restore_rtx);
- rtx_insn *new_insns = get_insns ();
- end_sequence ();
- lra_assert (single_set (new_insns) != NULL
- && SET_DEST (set) == SET_DEST (single_set (new_insns)));
- lra_process_new_insns (curr_insn, NULL, new_insns,
- "Changing reload<-invariant inheritance");
- delete_move_and_clobber (curr_insn, dregno);
- done_p = true;
- }
- else if ((bitmap_bit_p (remove_pseudos, sregno)
- && (get_regno (lra_reg_info[sregno].restore_rtx) == dregno
- || (bitmap_bit_p (remove_pseudos, dregno)
- && get_regno (lra_reg_info[sregno].restore_rtx) >= 0
- && (get_regno (lra_reg_info[sregno].restore_rtx)
- == get_regno (lra_reg_info[dregno].restore_rtx)))))
- || (bitmap_bit_p (remove_pseudos, dregno)
- && get_regno (lra_reg_info[dregno].restore_rtx) == sregno))
- /* One of the following cases:
- original <- removed inheritance pseudo
- removed inherit pseudo <- another removed inherit pseudo
- removed inherit pseudo <- original pseudo
- Or
- removed_split_pseudo <- original_reg
- original_reg <- removed_split_pseudo */
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Removing %s:\n",
- bitmap_bit_p (&lra_split_regs, sregno)
- || bitmap_bit_p (&lra_split_regs, dregno)
- ? "split" : "inheritance");
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- delete_move_and_clobber (curr_insn, dregno);
- done_p = true;
- }
- else if (bitmap_bit_p (remove_pseudos, sregno)
- && bitmap_bit_p (&lra_inheritance_pseudos, sregno))
- {
- /* Search the following pattern:
- inherit_or_split_pseudo1 <- inherit_or_split_pseudo2
- original_pseudo <- inherit_or_split_pseudo1
- where the 2nd insn is the current insn and
- inherit_or_split_pseudo2 is not removed. If it is found,
- change the current insn onto:
- original_pseudo <- inherit_or_split_pseudo2. */
- for (prev_insn = PREV_INSN (curr_insn);
- prev_insn != NULL_RTX && ! NONDEBUG_INSN_P (prev_insn);
- prev_insn = PREV_INSN (prev_insn))
- ;
- if (prev_insn != NULL_RTX && BLOCK_FOR_INSN (prev_insn) == bb
- && (prev_set = single_set (prev_insn)) != NULL_RTX
- /* There should be no subregs in insn we are
- searching because only the original reg might
- be in subreg when we changed the mode of
- load/store for splitting. */
- && REG_P (SET_DEST (prev_set))
- && REG_P (SET_SRC (prev_set))
- && (int) REGNO (SET_DEST (prev_set)) == sregno
- && ((prev_sregno = REGNO (SET_SRC (prev_set)))
- >= FIRST_PSEUDO_REGISTER)
- && (lra_reg_info[prev_sregno].restore_rtx == NULL_RTX
- ||
- /* As we consider chain of inheritance or
- splitting described in above comment we should
- check that sregno and prev_sregno were
- inheritance/split pseudos created from the
- same original regno. */
- (get_regno (lra_reg_info[sregno].restore_rtx) >= 0
- && (get_regno (lra_reg_info[sregno].restore_rtx)
- == get_regno (lra_reg_info[prev_sregno].restore_rtx))))
- && ! bitmap_bit_p (remove_pseudos, prev_sregno))
- {
- lra_assert (GET_MODE (SET_SRC (prev_set))
- == GET_MODE (regno_reg_rtx[sregno]));
- /* Although we have a single set, the insn can
- contain more one sregno register occurrence
- as a source. Change all occurrences. */
- lra_substitute_pseudo_within_insn (curr_insn, sregno,
- SET_SRC (prev_set),
- false);
- /* As we are finishing with processing the insn
- here, check the destination too as it might
- inheritance pseudo for another pseudo. */
- if (bitmap_bit_p (remove_pseudos, dregno)
- && bitmap_bit_p (&lra_inheritance_pseudos, dregno)
- && (restore_rtx
- = lra_reg_info[dregno].restore_rtx) != NULL_RTX)
- {
- if (GET_CODE (SET_DEST (set)) == SUBREG)
- SUBREG_REG (SET_DEST (set)) = restore_rtx;
- else
- SET_DEST (set) = restore_rtx;
- }
- lra_push_insn_and_update_insn_regno_info (curr_insn);
- lra_set_used_insn_alternative_by_uid
- (INSN_UID (curr_insn), LRA_UNKNOWN_ALT);
- done_p = true;
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Change reload insn:\n");
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- }
- }
- }
- if (! done_p)
- {
- struct lra_insn_reg *reg;
- bool restored_regs_p = false;
- bool kept_regs_p = false;
-
- curr_id = lra_get_insn_recog_data (curr_insn);
- for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- {
- regno = reg->regno;
- restore_rtx = lra_reg_info[regno].restore_rtx;
- if (restore_rtx != NULL_RTX)
- {
- if (change_p && bitmap_bit_p (remove_pseudos, regno))
- {
- lra_substitute_pseudo_within_insn
- (curr_insn, regno, restore_rtx, false);
- restored_regs_p = true;
- }
- else
- kept_regs_p = true;
- }
- }
- if (NONDEBUG_INSN_P (curr_insn) && kept_regs_p)
- {
- /* The instruction has changed since the previous
- constraints pass. */
- lra_push_insn_and_update_insn_regno_info (curr_insn);
- lra_set_used_insn_alternative_by_uid
- (INSN_UID (curr_insn), LRA_UNKNOWN_ALT);
- }
- else if (restored_regs_p)
- /* The instruction has been restored to the form that
- it had during the previous constraints pass. */
- lra_update_insn_regno_info (curr_insn);
- if (restored_regs_p && lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Insn after restoring regs:\n");
- dump_insn_slim (lra_dump_file, curr_insn);
- }
- }
- }
- }
- return change_p;
-}
-
-/* If optional reload pseudos failed to get a hard register or was not
- inherited, it is better to remove optional reloads. We do this
- transformation after undoing inheritance to figure out necessity to
- remove optional reloads easier. Return true if we do any
- change. */
-static bool
-undo_optional_reloads (void)
-{
- bool change_p, keep_p;
- unsigned int regno, uid;
- bitmap_iterator bi, bi2;
- rtx_insn *insn;
- rtx set, src, dest;
- auto_bitmap removed_optional_reload_pseudos (&reg_obstack);
-
- bitmap_copy (removed_optional_reload_pseudos, &lra_optional_reload_pseudos);
- EXECUTE_IF_SET_IN_BITMAP (&lra_optional_reload_pseudos, 0, regno, bi)
- {
- keep_p = false;
- /* Keep optional reloads from previous subpasses. */
- if (lra_reg_info[regno].restore_rtx == NULL_RTX
- /* If the original pseudo changed its allocation, just
- removing the optional pseudo is dangerous as the original
- pseudo will have longer live range. */
- || reg_renumber[REGNO (lra_reg_info[regno].restore_rtx)] >= 0)
- keep_p = true;
- else if (reg_renumber[regno] >= 0)
- EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi2)
- {
- insn = lra_insn_recog_data[uid]->insn;
- if ((set = single_set (insn)) == NULL_RTX)
- continue;
- src = SET_SRC (set);
- dest = SET_DEST (set);
- if (! REG_P (src) || ! REG_P (dest))
- continue;
- if (REGNO (dest) == regno
- /* Ignore insn for optional reloads itself. */
- && REGNO (lra_reg_info[regno].restore_rtx) != REGNO (src)
- /* Check only inheritance on last inheritance pass. */
- && (int) REGNO (src) >= new_regno_start
- /* Check that the optional reload was inherited. */
- && bitmap_bit_p (&lra_inheritance_pseudos, REGNO (src)))
- {
- keep_p = true;
- break;
- }
- }
- if (keep_p)
- {
- bitmap_clear_bit (removed_optional_reload_pseudos, regno);
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "Keep optional reload reg %d\n", regno);
- }
- }
- change_p = ! bitmap_empty_p (removed_optional_reload_pseudos);
- auto_bitmap insn_bitmap (&reg_obstack);
- EXECUTE_IF_SET_IN_BITMAP (removed_optional_reload_pseudos, 0, regno, bi)
- {
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, "Remove optional reload reg %d\n", regno);
- bitmap_copy (insn_bitmap, &lra_reg_info[regno].insn_bitmap);
- EXECUTE_IF_SET_IN_BITMAP (insn_bitmap, 0, uid, bi2)
- {
- insn = lra_insn_recog_data[uid]->insn;
- if ((set = single_set (insn)) != NULL_RTX)
- {
- src = SET_SRC (set);
- dest = SET_DEST (set);
- if (REG_P (src) && REG_P (dest)
- && ((REGNO (src) == regno
- && (REGNO (lra_reg_info[regno].restore_rtx)
- == REGNO (dest)))
- || (REGNO (dest) == regno
- && (REGNO (lra_reg_info[regno].restore_rtx)
- == REGNO (src)))))
- {
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file, " Deleting move %u\n",
- INSN_UID (insn));
- dump_insn_slim (lra_dump_file, insn);
- }
- delete_move_and_clobber (insn, REGNO (dest));
- continue;
- }
- /* We should not worry about generation memory-memory
- moves here as if the corresponding inheritance did
- not work (inheritance pseudo did not get a hard reg),
- we remove the inheritance pseudo and the optional
- reload. */
- }
- lra_substitute_pseudo_within_insn
- (insn, regno, lra_reg_info[regno].restore_rtx, false);
- lra_update_insn_regno_info (insn);
- if (lra_dump_file != NULL)
- {
- fprintf (lra_dump_file,
- " Restoring original insn:\n");
- dump_insn_slim (lra_dump_file, insn);
- }
- }
- }
- /* Clear restore_regnos. */
- EXECUTE_IF_SET_IN_BITMAP (&lra_optional_reload_pseudos, 0, regno, bi)
- lra_reg_info[regno].restore_rtx = NULL_RTX;
- return change_p;
-}
-
-/* Entry function for undoing inheritance/split transformation. Return true
- if we did any RTL change in this pass. */
-bool
-lra_undo_inheritance (void)
-{
- unsigned int regno;
- int hard_regno;
- int n_all_inherit, n_inherit, n_all_split, n_split;
- rtx restore_rtx;
- bitmap_iterator bi;
- bool change_p;
-
- lra_undo_inheritance_iter++;
- if (lra_undo_inheritance_iter > LRA_MAX_INHERITANCE_PASSES)
- return false;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- "\n********** Undoing inheritance #%d: **********\n\n",
- lra_undo_inheritance_iter);
- auto_bitmap remove_pseudos (&reg_obstack);
- n_inherit = n_all_inherit = 0;
- EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi)
- if (lra_reg_info[regno].restore_rtx != NULL_RTX)
- {
- n_all_inherit++;
- if (reg_renumber[regno] < 0
- /* If the original pseudo changed its allocation, just
- removing inheritance is dangerous as for changing
- allocation we used shorter live-ranges. */
- && (! REG_P (lra_reg_info[regno].restore_rtx)
- || reg_renumber[REGNO (lra_reg_info[regno].restore_rtx)] < 0))
- bitmap_set_bit (remove_pseudos, regno);
- else
- n_inherit++;
- }
- if (lra_dump_file != NULL && n_all_inherit != 0)
- fprintf (lra_dump_file, "Inherit %d out of %d (%.2f%%)\n",
- n_inherit, n_all_inherit,
- (double) n_inherit / n_all_inherit * 100);
- n_split = n_all_split = 0;
- EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi)
- if ((restore_rtx = lra_reg_info[regno].restore_rtx) != NULL_RTX)
- {
- int restore_regno = REGNO (restore_rtx);
-
- n_all_split++;
- hard_regno = (restore_regno >= FIRST_PSEUDO_REGISTER
- ? reg_renumber[restore_regno] : restore_regno);
- if (hard_regno < 0 || reg_renumber[regno] == hard_regno)
- bitmap_set_bit (remove_pseudos, regno);
- else
- {
- n_split++;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Keep split r%d (orig=r%d)\n",
- regno, restore_regno);
- }
- }
- if (lra_dump_file != NULL && n_all_split != 0)
- fprintf (lra_dump_file, "Split %d out of %d (%.2f%%)\n",
- n_split, n_all_split,
- (double) n_split / n_all_split * 100);
- change_p = remove_inheritance_pseudos (remove_pseudos);
- /* Clear restore_regnos. */
- EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi)
- lra_reg_info[regno].restore_rtx = NULL_RTX;
- EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi)
- lra_reg_info[regno].restore_rtx = NULL_RTX;
- change_p = undo_optional_reloads () || change_p;
- return change_p;
-}