aboutsummaryrefslogtreecommitdiff
path: root/gcc/ira.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/ira.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/ira.c')
-rw-r--r--gcc/ira.c6132
1 files changed, 0 insertions, 6132 deletions
diff --git a/gcc/ira.c b/gcc/ira.c
deleted file mode 100644
index 3bece66..0000000
--- a/gcc/ira.c
+++ /dev/null
@@ -1,6132 +0,0 @@
-/* Integrated Register Allocator (IRA) entry point.
- Copyright (C) 2006-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/>. */
-
-/* The integrated register allocator (IRA) is a
- regional register allocator performing graph coloring on a top-down
- traversal of nested regions. Graph coloring in a region is based
- on Chaitin-Briggs algorithm. It is called integrated because
- register coalescing, register live range splitting, and choosing a
- better hard register are done on-the-fly during coloring. Register
- coalescing and choosing a cheaper hard register is done by hard
- register preferencing during hard register assigning. The live
- range splitting is a byproduct of the regional register allocation.
-
- Major IRA notions are:
-
- o *Region* is a part of CFG where graph coloring based on
- Chaitin-Briggs algorithm is done. IRA can work on any set of
- nested CFG regions forming a tree. Currently the regions are
- the entire function for the root region and natural loops for
- the other regions. Therefore data structure representing a
- region is called loop_tree_node.
-
- o *Allocno class* is a register class used for allocation of
- given allocno. It means that only hard register of given
- register class can be assigned to given allocno. In reality,
- even smaller subset of (*profitable*) hard registers can be
- assigned. In rare cases, the subset can be even smaller
- because our modification of Chaitin-Briggs algorithm requires
- that sets of hard registers can be assigned to allocnos forms a
- forest, i.e. the sets can be ordered in a way where any
- previous set is not intersected with given set or is a superset
- of given set.
-
- o *Pressure class* is a register class belonging to a set of
- register classes containing all of the hard-registers available
- for register allocation. The set of all pressure classes for a
- target is defined in the corresponding machine-description file
- according some criteria. Register pressure is calculated only
- for pressure classes and it affects some IRA decisions as
- forming allocation regions.
-
- o *Allocno* represents the live range of a pseudo-register in a
- region. Besides the obvious attributes like the corresponding
- pseudo-register number, allocno class, conflicting allocnos and
- conflicting hard-registers, there are a few allocno attributes
- which are important for understanding the allocation algorithm:
-
- - *Live ranges*. This is a list of ranges of *program points*
- where the allocno lives. Program points represent places
- where a pseudo can be born or become dead (there are
- approximately two times more program points than the insns)
- and they are represented by integers starting with 0. The
- live ranges are used to find conflicts between allocnos.
- They also play very important role for the transformation of
- the IRA internal representation of several regions into a one
- region representation. The later is used during the reload
- pass work because each allocno represents all of the
- corresponding pseudo-registers.
-
- - *Hard-register costs*. This is a vector of size equal to the
- number of available hard-registers of the allocno class. The
- cost of a callee-clobbered hard-register for an allocno is
- increased by the cost of save/restore code around the calls
- through the given allocno's life. If the allocno is a move
- instruction operand and another operand is a hard-register of
- the allocno class, the cost of the hard-register is decreased
- by the move cost.
-
- When an allocno is assigned, the hard-register with minimal
- full cost is used. Initially, a hard-register's full cost is
- the corresponding value from the hard-register's cost vector.
- If the allocno is connected by a *copy* (see below) to
- another allocno which has just received a hard-register, the
- cost of the hard-register is decreased. Before choosing a
- hard-register for an allocno, the allocno's current costs of
- the hard-registers are modified by the conflict hard-register
- costs of all of the conflicting allocnos which are not
- assigned yet.
-
- - *Conflict hard-register costs*. This is a vector of the same
- size as the hard-register costs vector. To permit an
- unassigned allocno to get a better hard-register, IRA uses
- this vector to calculate the final full cost of the
- available hard-registers. Conflict hard-register costs of an
- unassigned allocno are also changed with a change of the
- hard-register cost of the allocno when a copy involving the
- allocno is processed as described above. This is done to
- show other unassigned allocnos that a given allocno prefers
- some hard-registers in order to remove the move instruction
- corresponding to the copy.
-
- o *Cap*. If a pseudo-register does not live in a region but
- lives in a nested region, IRA creates a special allocno called
- a cap in the outer region. A region cap is also created for a
- subregion cap.
-
- o *Copy*. Allocnos can be connected by copies. Copies are used
- to modify hard-register costs for allocnos during coloring.
- Such modifications reflects a preference to use the same
- hard-register for the allocnos connected by copies. Usually
- copies are created for move insns (in this case it results in
- register coalescing). But IRA also creates copies for operands
- of an insn which should be assigned to the same hard-register
- due to constraints in the machine description (it usually
- results in removing a move generated in reload to satisfy
- the constraints) and copies referring to the allocno which is
- the output operand of an instruction and the allocno which is
- an input operand dying in the instruction (creation of such
- copies results in less register shuffling). IRA *does not*
- create copies between the same register allocnos from different
- regions because we use another technique for propagating
- hard-register preference on the borders of regions.
-
- Allocnos (including caps) for the upper region in the region tree
- *accumulate* information important for coloring from allocnos with
- the same pseudo-register from nested regions. This includes
- hard-register and memory costs, conflicts with hard-registers,
- allocno conflicts, allocno copies and more. *Thus, attributes for
- allocnos in a region have the same values as if the region had no
- subregions*. It means that attributes for allocnos in the
- outermost region corresponding to the function have the same values
- as though the allocation used only one region which is the entire
- function. It also means that we can look at IRA work as if the
- first IRA did allocation for all function then it improved the
- allocation for loops then their subloops and so on.
-
- IRA major passes are:
-
- o Building IRA internal representation which consists of the
- following subpasses:
-
- * First, IRA builds regions and creates allocnos (file
- ira-build.c) and initializes most of their attributes.
-
- * Then IRA finds an allocno class for each allocno and
- calculates its initial (non-accumulated) cost of memory and
- each hard-register of its allocno class (file ira-cost.c).
-
- * IRA creates live ranges of each allocno, calculates register
- pressure for each pressure class in each region, sets up
- conflict hard registers for each allocno and info about calls
- the allocno lives through (file ira-lives.c).
-
- * IRA removes low register pressure loops from the regions
- mostly to speed IRA up (file ira-build.c).
-
- * IRA propagates accumulated allocno info from lower region
- allocnos to corresponding upper region allocnos (file
- ira-build.c).
-
- * IRA creates all caps (file ira-build.c).
-
- * Having live-ranges of allocnos and their classes, IRA creates
- conflicting allocnos for each allocno. Conflicting allocnos
- are stored as a bit vector or array of pointers to the
- conflicting allocnos whatever is more profitable (file
- ira-conflicts.c). At this point IRA creates allocno copies.
-
- o Coloring. Now IRA has all necessary info to start graph coloring
- process. It is done in each region on top-down traverse of the
- region tree (file ira-color.c). There are following subpasses:
-
- * Finding profitable hard registers of corresponding allocno
- class for each allocno. For example, only callee-saved hard
- registers are frequently profitable for allocnos living
- through colors. If the profitable hard register set of
- allocno does not form a tree based on subset relation, we use
- some approximation to form the tree. This approximation is
- used to figure out trivial colorability of allocnos. The
- approximation is a pretty rare case.
-
- * Putting allocnos onto the coloring stack. IRA uses Briggs
- optimistic coloring which is a major improvement over
- Chaitin's coloring. Therefore IRA does not spill allocnos at
- this point. There is some freedom in the order of putting
- allocnos on the stack which can affect the final result of
- the allocation. IRA uses some heuristics to improve the
- order. The major one is to form *threads* from colorable
- allocnos and push them on the stack by threads. Thread is a
- set of non-conflicting colorable allocnos connected by
- copies. The thread contains allocnos from the colorable
- bucket or colorable allocnos already pushed onto the coloring
- stack. Pushing thread allocnos one after another onto the
- stack increases chances of removing copies when the allocnos
- get the same hard reg.
-
- We also use a modification of Chaitin-Briggs algorithm which
- works for intersected register classes of allocnos. To
- figure out trivial colorability of allocnos, the mentioned
- above tree of hard register sets is used. To get an idea how
- the algorithm works in i386 example, let us consider an
- allocno to which any general hard register can be assigned.
- If the allocno conflicts with eight allocnos to which only
- EAX register can be assigned, given allocno is still
- trivially colorable because all conflicting allocnos might be
- assigned only to EAX and all other general hard registers are
- still free.
-
- To get an idea of the used trivial colorability criterion, it
- is also useful to read article "Graph-Coloring Register
- Allocation for Irregular Architectures" by Michael D. Smith
- and Glen Holloway. Major difference between the article
- approach and approach used in IRA is that Smith's approach
- takes register classes only from machine description and IRA
- calculate register classes from intermediate code too
- (e.g. an explicit usage of hard registers in RTL code for
- parameter passing can result in creation of additional
- register classes which contain or exclude the hard
- registers). That makes IRA approach useful for improving
- coloring even for architectures with regular register files
- and in fact some benchmarking shows the improvement for
- regular class architectures is even bigger than for irregular
- ones. Another difference is that Smith's approach chooses
- intersection of classes of all insn operands in which a given
- pseudo occurs. IRA can use bigger classes if it is still
- more profitable than memory usage.
-
- * Popping the allocnos from the stack and assigning them hard
- registers. If IRA cannot assign a hard register to an
- allocno and the allocno is coalesced, IRA undoes the
- coalescing and puts the uncoalesced allocnos onto the stack in
- the hope that some such allocnos will get a hard register
- separately. If IRA fails to assign hard register or memory
- is more profitable for it, IRA spills the allocno. IRA
- assigns the allocno the hard-register with minimal full
- allocation cost which reflects the cost of usage of the
- hard-register for the allocno and cost of usage of the
- hard-register for allocnos conflicting with given allocno.
-
- * Chaitin-Briggs coloring assigns as many pseudos as possible
- to hard registers. After coloring we try to improve
- allocation with cost point of view. We improve the
- allocation by spilling some allocnos and assigning the freed
- hard registers to other allocnos if it decreases the overall
- allocation cost.
-
- * After allocno assigning in the region, IRA modifies the hard
- register and memory costs for the corresponding allocnos in
- the subregions to reflect the cost of possible loads, stores,
- or moves on the border of the region and its subregions.
- When default regional allocation algorithm is used
- (-fira-algorithm=mixed), IRA just propagates the assignment
- for allocnos if the register pressure in the region for the
- corresponding pressure class is less than number of available
- hard registers for given pressure class.
-
- o Spill/restore code moving. When IRA performs an allocation
- by traversing regions in top-down order, it does not know what
- happens below in the region tree. Therefore, sometimes IRA
- misses opportunities to perform a better allocation. A simple
- optimization tries to improve allocation in a region having
- subregions and containing in another region. If the
- corresponding allocnos in the subregion are spilled, it spills
- the region allocno if it is profitable. The optimization
- implements a simple iterative algorithm performing profitable
- transformations while they are still possible. It is fast in
- practice, so there is no real need for a better time complexity
- algorithm.
-
- o Code change. After coloring, two allocnos representing the
- same pseudo-register outside and inside a region respectively
- may be assigned to different locations (hard-registers or
- memory). In this case IRA creates and uses a new
- pseudo-register inside the region and adds code to move allocno
- values on the region's borders. This is done during top-down
- traversal of the regions (file ira-emit.c). In some
- complicated cases IRA can create a new allocno to move allocno
- values (e.g. when a swap of values stored in two hard-registers
- is needed). At this stage, the new allocno is marked as
- spilled. IRA still creates the pseudo-register and the moves
- on the region borders even when both allocnos were assigned to
- the same hard-register. If the reload pass spills a
- pseudo-register for some reason, the effect will be smaller
- because another allocno will still be in the hard-register. In
- most cases, this is better then spilling both allocnos. If
- reload does not change the allocation for the two
- pseudo-registers, the trivial move will be removed by
- post-reload optimizations. IRA does not generate moves for
- allocnos assigned to the same hard register when the default
- regional allocation algorithm is used and the register pressure
- in the region for the corresponding pressure class is less than
- number of available hard registers for given pressure class.
- IRA also does some optimizations to remove redundant stores and
- to reduce code duplication on the region borders.
-
- o Flattening internal representation. After changing code, IRA
- transforms its internal representation for several regions into
- one region representation (file ira-build.c). This process is
- called IR flattening. Such process is more complicated than IR
- rebuilding would be, but is much faster.
-
- o After IR flattening, IRA tries to assign hard registers to all
- spilled allocnos. This is implemented by a simple and fast
- priority coloring algorithm (see function
- ira_reassign_conflict_allocnos::ira-color.c). Here new allocnos
- created during the code change pass can be assigned to hard
- registers.
-
- o At the end IRA calls the reload pass. The reload pass
- communicates with IRA through several functions in file
- ira-color.c to improve its decisions in
-
- * sharing stack slots for the spilled pseudos based on IRA info
- about pseudo-register conflicts.
-
- * reassigning hard-registers to all spilled pseudos at the end
- of each reload iteration.
-
- * choosing a better hard-register to spill based on IRA info
- about pseudo-register live ranges and the register pressure
- in places where the pseudo-register lives.
-
- IRA uses a lot of data representing the target processors. These
- data are initialized in file ira.c.
-
- If function has no loops (or the loops are ignored when
- -fira-algorithm=CB is used), we have classic Chaitin-Briggs
- coloring (only instead of separate pass of coalescing, we use hard
- register preferencing). In such case, IRA works much faster
- because many things are not made (like IR flattening, the
- spill/restore optimization, and the code change).
-
- Literature is worth to read for better understanding the code:
-
- o Preston Briggs, Keith D. Cooper, Linda Torczon. Improvements to
- Graph Coloring Register Allocation.
-
- o David Callahan, Brian Koblenz. Register allocation via
- hierarchical graph coloring.
-
- o Keith Cooper, Anshuman Dasgupta, Jason Eckhardt. Revisiting Graph
- Coloring Register Allocation: A Study of the Chaitin-Briggs and
- Callahan-Koblenz Algorithms.
-
- o Guei-Yuan Lueh, Thomas Gross, and Ali-Reza Adl-Tabatabai. Global
- Register Allocation Based on Graph Fusion.
-
- o Michael D. Smith and Glenn Holloway. Graph-Coloring Register
- Allocation for Irregular Architectures
-
- o Vladimir Makarov. The Integrated Register Allocator for GCC.
-
- o Vladimir Makarov. The top-down register allocator for irregular
- register file architectures.
-
-*/
-
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "target.h"
-#include "rtl.h"
-#include "tree.h"
-#include "df.h"
-#include "memmodel.h"
-#include "tm_p.h"
-#include "insn-config.h"
-#include "regs.h"
-#include "ira.h"
-#include "ira-int.h"
-#include "diagnostic-core.h"
-#include "cfgrtl.h"
-#include "cfgbuild.h"
-#include "cfgcleanup.h"
-#include "expr.h"
-#include "tree-pass.h"
-#include "output.h"
-#include "reload.h"
-#include "cfgloop.h"
-#include "lra.h"
-#include "dce.h"
-#include "dbgcnt.h"
-#include "rtl-iter.h"
-#include "shrink-wrap.h"
-#include "print-rtl.h"
-
-struct target_ira default_target_ira;
-class target_ira_int default_target_ira_int;
-#if SWITCHABLE_TARGET
-struct target_ira *this_target_ira = &default_target_ira;
-class target_ira_int *this_target_ira_int = &default_target_ira_int;
-#endif
-
-/* A modified value of flag `-fira-verbose' used internally. */
-int internal_flag_ira_verbose;
-
-/* Dump file of the allocator if it is not NULL. */
-FILE *ira_dump_file;
-
-/* The number of elements in the following array. */
-int ira_spilled_reg_stack_slots_num;
-
-/* The following array contains info about spilled pseudo-registers
- stack slots used in current function so far. */
-class ira_spilled_reg_stack_slot *ira_spilled_reg_stack_slots;
-
-/* Correspondingly overall cost of the allocation, overall cost before
- reload, cost of the allocnos assigned to hard-registers, cost of
- the allocnos assigned to memory, cost of loads, stores and register
- move insns generated for pseudo-register live range splitting (see
- ira-emit.c). */
-int64_t ira_overall_cost, overall_cost_before;
-int64_t ira_reg_cost, ira_mem_cost;
-int64_t ira_load_cost, ira_store_cost, ira_shuffle_cost;
-int ira_move_loops_num, ira_additional_jumps_num;
-
-/* All registers that can be eliminated. */
-
-HARD_REG_SET eliminable_regset;
-
-/* Value of max_reg_num () before IRA work start. This value helps
- us to recognize a situation when new pseudos were created during
- IRA work. */
-static int max_regno_before_ira;
-
-/* Temporary hard reg set used for a different calculation. */
-static HARD_REG_SET temp_hard_regset;
-
-#define last_mode_for_init_move_cost \
- (this_target_ira_int->x_last_mode_for_init_move_cost)
-
-
-/* The function sets up the map IRA_REG_MODE_HARD_REGSET. */
-static void
-setup_reg_mode_hard_regset (void)
-{
- int i, m, hard_regno;
-
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- for (hard_regno = 0; hard_regno < FIRST_PSEUDO_REGISTER; hard_regno++)
- {
- CLEAR_HARD_REG_SET (ira_reg_mode_hard_regset[hard_regno][m]);
- for (i = hard_regno_nregs (hard_regno, (machine_mode) m) - 1;
- i >= 0; i--)
- if (hard_regno + i < FIRST_PSEUDO_REGISTER)
- SET_HARD_REG_BIT (ira_reg_mode_hard_regset[hard_regno][m],
- hard_regno + i);
- }
-}
-
-
-#define no_unit_alloc_regs \
- (this_target_ira_int->x_no_unit_alloc_regs)
-
-/* The function sets up the three arrays declared above. */
-static void
-setup_class_hard_regs (void)
-{
- int cl, i, hard_regno, n;
- HARD_REG_SET processed_hard_reg_set;
-
- ira_assert (SHRT_MAX >= FIRST_PSEUDO_REGISTER);
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- temp_hard_regset = reg_class_contents[cl] & ~no_unit_alloc_regs;
- CLEAR_HARD_REG_SET (processed_hard_reg_set);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- ira_non_ordered_class_hard_regs[cl][i] = -1;
- ira_class_hard_reg_index[cl][i] = -1;
- }
- for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
-#ifdef REG_ALLOC_ORDER
- hard_regno = reg_alloc_order[i];
-#else
- hard_regno = i;
-#endif
- if (TEST_HARD_REG_BIT (processed_hard_reg_set, hard_regno))
- continue;
- SET_HARD_REG_BIT (processed_hard_reg_set, hard_regno);
- if (! TEST_HARD_REG_BIT (temp_hard_regset, hard_regno))
- ira_class_hard_reg_index[cl][hard_regno] = -1;
- else
- {
- ira_class_hard_reg_index[cl][hard_regno] = n;
- ira_class_hard_regs[cl][n++] = hard_regno;
- }
- }
- ira_class_hard_regs_num[cl] = n;
- for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (temp_hard_regset, i))
- ira_non_ordered_class_hard_regs[cl][n++] = i;
- ira_assert (ira_class_hard_regs_num[cl] == n);
- }
-}
-
-/* Set up global variables defining info about hard registers for the
- allocation. These depend on USE_HARD_FRAME_P whose TRUE value means
- that we can use the hard frame pointer for the allocation. */
-static void
-setup_alloc_regs (bool use_hard_frame_p)
-{
-#ifdef ADJUST_REG_ALLOC_ORDER
- ADJUST_REG_ALLOC_ORDER;
-#endif
- no_unit_alloc_regs = fixed_nonglobal_reg_set;
- if (! use_hard_frame_p)
- add_to_hard_reg_set (&no_unit_alloc_regs, Pmode,
- HARD_FRAME_POINTER_REGNUM);
- setup_class_hard_regs ();
-}
-
-
-
-#define alloc_reg_class_subclasses \
- (this_target_ira_int->x_alloc_reg_class_subclasses)
-
-/* Initialize the table of subclasses of each reg class. */
-static void
-setup_reg_subclasses (void)
-{
- int i, j;
- HARD_REG_SET temp_hard_regset2;
-
- for (i = 0; i < N_REG_CLASSES; i++)
- for (j = 0; j < N_REG_CLASSES; j++)
- alloc_reg_class_subclasses[i][j] = LIM_REG_CLASSES;
-
- for (i = 0; i < N_REG_CLASSES; i++)
- {
- if (i == (int) NO_REGS)
- continue;
-
- temp_hard_regset = reg_class_contents[i] & ~no_unit_alloc_regs;
- if (hard_reg_set_empty_p (temp_hard_regset))
- continue;
- for (j = 0; j < N_REG_CLASSES; j++)
- if (i != j)
- {
- enum reg_class *p;
-
- temp_hard_regset2 = reg_class_contents[j] & ~no_unit_alloc_regs;
- if (! hard_reg_set_subset_p (temp_hard_regset,
- temp_hard_regset2))
- continue;
- p = &alloc_reg_class_subclasses[j][0];
- while (*p != LIM_REG_CLASSES) p++;
- *p = (enum reg_class) i;
- }
- }
-}
-
-
-
-/* Set up IRA_MEMORY_MOVE_COST and IRA_MAX_MEMORY_MOVE_COST. */
-static void
-setup_class_subset_and_memory_move_costs (void)
-{
- int cl, cl2, mode, cost;
- HARD_REG_SET temp_hard_regset2;
-
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- ira_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][NO_REGS][1] = SHRT_MAX;
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- if (cl != (int) NO_REGS)
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- ira_max_memory_move_cost[mode][cl][0]
- = ira_memory_move_cost[mode][cl][0]
- = memory_move_cost ((machine_mode) mode,
- (reg_class_t) cl, false);
- ira_max_memory_move_cost[mode][cl][1]
- = ira_memory_move_cost[mode][cl][1]
- = memory_move_cost ((machine_mode) mode,
- (reg_class_t) cl, true);
- /* Costs for NO_REGS are used in cost calculation on the
- 1st pass when the preferred register classes are not
- known yet. In this case we take the best scenario. */
- if (ira_memory_move_cost[mode][NO_REGS][0]
- > ira_memory_move_cost[mode][cl][0])
- ira_max_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][cl][0];
- if (ira_memory_move_cost[mode][NO_REGS][1]
- > ira_memory_move_cost[mode][cl][1])
- ira_max_memory_move_cost[mode][NO_REGS][1]
- = ira_memory_move_cost[mode][NO_REGS][1]
- = ira_memory_move_cost[mode][cl][1];
- }
- }
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (cl2 = (int) N_REG_CLASSES - 1; cl2 >= 0; cl2--)
- {
- temp_hard_regset = reg_class_contents[cl] & ~no_unit_alloc_regs;
- temp_hard_regset2 = reg_class_contents[cl2] & ~no_unit_alloc_regs;
- ira_class_subset_p[cl][cl2]
- = hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2);
- if (! hard_reg_set_empty_p (temp_hard_regset2)
- && hard_reg_set_subset_p (reg_class_contents[cl2],
- reg_class_contents[cl]))
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- cost = ira_memory_move_cost[mode][cl2][0];
- if (cost > ira_max_memory_move_cost[mode][cl][0])
- ira_max_memory_move_cost[mode][cl][0] = cost;
- cost = ira_memory_move_cost[mode][cl2][1];
- if (cost > ira_max_memory_move_cost[mode][cl][1])
- ira_max_memory_move_cost[mode][cl][1] = cost;
- }
- }
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- ira_memory_move_cost[mode][cl][0]
- = ira_max_memory_move_cost[mode][cl][0];
- ira_memory_move_cost[mode][cl][1]
- = ira_max_memory_move_cost[mode][cl][1];
- }
- setup_reg_subclasses ();
-}
-
-
-
-/* Define the following macro if allocation through malloc if
- preferable. */
-#define IRA_NO_OBSTACK
-
-#ifndef IRA_NO_OBSTACK
-/* Obstack used for storing all dynamic data (except bitmaps) of the
- IRA. */
-static struct obstack ira_obstack;
-#endif
-
-/* Obstack used for storing all bitmaps of the IRA. */
-static struct bitmap_obstack ira_bitmap_obstack;
-
-/* Allocate memory of size LEN for IRA data. */
-void *
-ira_allocate (size_t len)
-{
- void *res;
-
-#ifndef IRA_NO_OBSTACK
- res = obstack_alloc (&ira_obstack, len);
-#else
- res = xmalloc (len);
-#endif
- return res;
-}
-
-/* Free memory ADDR allocated for IRA data. */
-void
-ira_free (void *addr ATTRIBUTE_UNUSED)
-{
-#ifndef IRA_NO_OBSTACK
- /* do nothing */
-#else
- free (addr);
-#endif
-}
-
-
-/* Allocate and returns bitmap for IRA. */
-bitmap
-ira_allocate_bitmap (void)
-{
- return BITMAP_ALLOC (&ira_bitmap_obstack);
-}
-
-/* Free bitmap B allocated for IRA. */
-void
-ira_free_bitmap (bitmap b ATTRIBUTE_UNUSED)
-{
- /* do nothing */
-}
-
-
-
-/* Output information about allocation of all allocnos (except for
- caps) into file F. */
-void
-ira_print_disposition (FILE *f)
-{
- int i, n, max_regno;
- ira_allocno_t a;
- basic_block bb;
-
- fprintf (f, "Disposition:");
- max_regno = max_reg_num ();
- for (n = 0, i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- for (a = ira_regno_allocno_map[i];
- a != NULL;
- a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
- {
- if (n % 4 == 0)
- fprintf (f, "\n");
- n++;
- fprintf (f, " %4d:r%-4d", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
- if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
- fprintf (f, "b%-3d", bb->index);
- else
- fprintf (f, "l%-3d", ALLOCNO_LOOP_TREE_NODE (a)->loop_num);
- if (ALLOCNO_HARD_REGNO (a) >= 0)
- fprintf (f, " %3d", ALLOCNO_HARD_REGNO (a));
- else
- fprintf (f, " mem");
- }
- fprintf (f, "\n");
-}
-
-/* Outputs information about allocation of all allocnos into
- stderr. */
-void
-ira_debug_disposition (void)
-{
- ira_print_disposition (stderr);
-}
-
-
-
-/* Set up ira_stack_reg_pressure_class which is the biggest pressure
- register class containing stack registers or NO_REGS if there are
- no stack registers. To find this class, we iterate through all
- register pressure classes and choose the first register pressure
- class containing all the stack registers and having the biggest
- size. */
-static void
-setup_stack_reg_pressure_class (void)
-{
- ira_stack_reg_pressure_class = NO_REGS;
-#ifdef STACK_REGS
- {
- int i, best, size;
- enum reg_class cl;
- HARD_REG_SET temp_hard_regset2;
-
- CLEAR_HARD_REG_SET (temp_hard_regset);
- for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
- SET_HARD_REG_BIT (temp_hard_regset, i);
- best = 0;
- for (i = 0; i < ira_pressure_classes_num; i++)
- {
- cl = ira_pressure_classes[i];
- temp_hard_regset2 = temp_hard_regset & reg_class_contents[cl];
- size = hard_reg_set_size (temp_hard_regset2);
- if (best < size)
- {
- best = size;
- ira_stack_reg_pressure_class = cl;
- }
- }
- }
-#endif
-}
-
-/* Find pressure classes which are register classes for which we
- calculate register pressure in IRA, register pressure sensitive
- insn scheduling, and register pressure sensitive loop invariant
- motion.
-
- To make register pressure calculation easy, we always use
- non-intersected register pressure classes. A move of hard
- registers from one register pressure class is not more expensive
- than load and store of the hard registers. Most likely an allocno
- class will be a subset of a register pressure class and in many
- cases a register pressure class. That makes usage of register
- pressure classes a good approximation to find a high register
- pressure. */
-static void
-setup_pressure_classes (void)
-{
- int cost, i, n, curr;
- int cl, cl2;
- enum reg_class pressure_classes[N_REG_CLASSES];
- int m;
- HARD_REG_SET temp_hard_regset2;
- bool insert_p;
-
- if (targetm.compute_pressure_classes)
- n = targetm.compute_pressure_classes (pressure_classes);
- else
- {
- n = 0;
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- if (ira_class_hard_regs_num[cl] == 0)
- continue;
- if (ira_class_hard_regs_num[cl] != 1
- /* A register class without subclasses may contain a few
- hard registers and movement between them is costly
- (e.g. SPARC FPCC registers). We still should consider it
- as a candidate for a pressure class. */
- && alloc_reg_class_subclasses[cl][0] < cl)
- {
- /* Check that the moves between any hard registers of the
- current class are not more expensive for a legal mode
- than load/store of the hard registers of the current
- class. Such class is a potential candidate to be a
- register pressure class. */
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- {
- temp_hard_regset
- = (reg_class_contents[cl]
- & ~(no_unit_alloc_regs
- | ira_prohibited_class_mode_regs[cl][m]));
- if (hard_reg_set_empty_p (temp_hard_regset))
- continue;
- ira_init_register_move_cost_if_necessary ((machine_mode) m);
- cost = ira_register_move_cost[m][cl][cl];
- if (cost <= ira_max_memory_move_cost[m][cl][1]
- || cost <= ira_max_memory_move_cost[m][cl][0])
- break;
- }
- if (m >= NUM_MACHINE_MODES)
- continue;
- }
- curr = 0;
- insert_p = true;
- temp_hard_regset = reg_class_contents[cl] & ~no_unit_alloc_regs;
- /* Remove so far added pressure classes which are subset of the
- current candidate class. Prefer GENERAL_REGS as a pressure
- register class to another class containing the same
- allocatable hard registers. We do this because machine
- dependent cost hooks might give wrong costs for the latter
- class but always give the right cost for the former class
- (GENERAL_REGS). */
- for (i = 0; i < n; i++)
- {
- cl2 = pressure_classes[i];
- temp_hard_regset2 = (reg_class_contents[cl2]
- & ~no_unit_alloc_regs);
- if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2)
- && (temp_hard_regset != temp_hard_regset2
- || cl2 == (int) GENERAL_REGS))
- {
- pressure_classes[curr++] = (enum reg_class) cl2;
- insert_p = false;
- continue;
- }
- if (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset)
- && (temp_hard_regset2 != temp_hard_regset
- || cl == (int) GENERAL_REGS))
- continue;
- if (temp_hard_regset2 == temp_hard_regset)
- insert_p = false;
- pressure_classes[curr++] = (enum reg_class) cl2;
- }
- /* If the current candidate is a subset of a so far added
- pressure class, don't add it to the list of the pressure
- classes. */
- if (insert_p)
- pressure_classes[curr++] = (enum reg_class) cl;
- n = curr;
- }
- }
-#ifdef ENABLE_IRA_CHECKING
- {
- HARD_REG_SET ignore_hard_regs;
-
- /* Check pressure classes correctness: here we check that hard
- registers from all register pressure classes contains all hard
- registers available for the allocation. */
- CLEAR_HARD_REG_SET (temp_hard_regset);
- CLEAR_HARD_REG_SET (temp_hard_regset2);
- ignore_hard_regs = no_unit_alloc_regs;
- for (cl = 0; cl < LIM_REG_CLASSES; cl++)
- {
- /* For some targets (like MIPS with MD_REGS), there are some
- classes with hard registers available for allocation but
- not able to hold value of any mode. */
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- if (contains_reg_of_mode[cl][m])
- break;
- if (m >= NUM_MACHINE_MODES)
- {
- ignore_hard_regs |= reg_class_contents[cl];
- continue;
- }
- for (i = 0; i < n; i++)
- if ((int) pressure_classes[i] == cl)
- break;
- temp_hard_regset2 |= reg_class_contents[cl];
- if (i < n)
- temp_hard_regset |= reg_class_contents[cl];
- }
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- /* Some targets (like SPARC with ICC reg) have allocatable regs
- for which no reg class is defined. */
- if (REGNO_REG_CLASS (i) == NO_REGS)
- SET_HARD_REG_BIT (ignore_hard_regs, i);
- temp_hard_regset &= ~ignore_hard_regs;
- temp_hard_regset2 &= ~ignore_hard_regs;
- ira_assert (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset));
- }
-#endif
- ira_pressure_classes_num = 0;
- for (i = 0; i < n; i++)
- {
- cl = (int) pressure_classes[i];
- ira_reg_pressure_class_p[cl] = true;
- ira_pressure_classes[ira_pressure_classes_num++] = (enum reg_class) cl;
- }
- setup_stack_reg_pressure_class ();
-}
-
-/* Set up IRA_UNIFORM_CLASS_P. Uniform class is a register class
- whose register move cost between any registers of the class is the
- same as for all its subclasses. We use the data to speed up the
- 2nd pass of calculations of allocno costs. */
-static void
-setup_uniform_class_p (void)
-{
- int i, cl, cl2, m;
-
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- ira_uniform_class_p[cl] = false;
- if (ira_class_hard_regs_num[cl] == 0)
- continue;
- /* We cannot use alloc_reg_class_subclasses here because move
- cost hooks does not take into account that some registers are
- unavailable for the subtarget. E.g. for i686, INT_SSE_REGS
- is element of alloc_reg_class_subclasses for GENERAL_REGS
- because SSE regs are unavailable. */
- for (i = 0; (cl2 = reg_class_subclasses[cl][i]) != LIM_REG_CLASSES; i++)
- {
- if (ira_class_hard_regs_num[cl2] == 0)
- continue;
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- if (contains_reg_of_mode[cl][m] && contains_reg_of_mode[cl2][m])
- {
- ira_init_register_move_cost_if_necessary ((machine_mode) m);
- if (ira_register_move_cost[m][cl][cl]
- != ira_register_move_cost[m][cl2][cl2])
- break;
- }
- if (m < NUM_MACHINE_MODES)
- break;
- }
- if (cl2 == LIM_REG_CLASSES)
- ira_uniform_class_p[cl] = true;
- }
-}
-
-/* Set up IRA_ALLOCNO_CLASSES, IRA_ALLOCNO_CLASSES_NUM,
- IRA_IMPORTANT_CLASSES, and IRA_IMPORTANT_CLASSES_NUM.
-
- Target may have many subtargets and not all target hard registers can
- be used for allocation, e.g. x86 port in 32-bit mode cannot use
- hard registers introduced in x86-64 like r8-r15). Some classes
- might have the same allocatable hard registers, e.g. INDEX_REGS
- and GENERAL_REGS in x86 port in 32-bit mode. To decrease different
- calculations efforts we introduce allocno classes which contain
- unique non-empty sets of allocatable hard-registers.
-
- Pseudo class cost calculation in ira-costs.c is very expensive.
- Therefore we are trying to decrease number of classes involved in
- such calculation. Register classes used in the cost calculation
- are called important classes. They are allocno classes and other
- non-empty classes whose allocatable hard register sets are inside
- of an allocno class hard register set. From the first sight, it
- looks like that they are just allocno classes. It is not true. In
- example of x86-port in 32-bit mode, allocno classes will contain
- GENERAL_REGS but not LEGACY_REGS (because allocatable hard
- registers are the same for the both classes). The important
- classes will contain GENERAL_REGS and LEGACY_REGS. It is done
- because a machine description insn constraint may refers for
- LEGACY_REGS and code in ira-costs.c is mostly base on investigation
- of the insn constraints. */
-static void
-setup_allocno_and_important_classes (void)
-{
- int i, j, n, cl;
- bool set_p;
- HARD_REG_SET temp_hard_regset2;
- static enum reg_class classes[LIM_REG_CLASSES + 1];
-
- n = 0;
- /* Collect classes which contain unique sets of allocatable hard
- registers. Prefer GENERAL_REGS to other classes containing the
- same set of hard registers. */
- for (i = 0; i < LIM_REG_CLASSES; i++)
- {
- temp_hard_regset = reg_class_contents[i] & ~no_unit_alloc_regs;
- for (j = 0; j < n; j++)
- {
- cl = classes[j];
- temp_hard_regset2 = reg_class_contents[cl] & ~no_unit_alloc_regs;
- if (temp_hard_regset == temp_hard_regset2)
- break;
- }
- if (j >= n || targetm.additional_allocno_class_p (i))
- classes[n++] = (enum reg_class) i;
- else if (i == GENERAL_REGS)
- /* Prefer general regs. For i386 example, it means that
- we prefer GENERAL_REGS over INDEX_REGS or LEGACY_REGS
- (all of them consists of the same available hard
- registers). */
- classes[j] = (enum reg_class) i;
- }
- classes[n] = LIM_REG_CLASSES;
-
- /* Set up classes which can be used for allocnos as classes
- containing non-empty unique sets of allocatable hard
- registers. */
- ira_allocno_classes_num = 0;
- for (i = 0; (cl = classes[i]) != LIM_REG_CLASSES; i++)
- if (ira_class_hard_regs_num[cl] > 0)
- ira_allocno_classes[ira_allocno_classes_num++] = (enum reg_class) cl;
- ira_important_classes_num = 0;
- /* Add non-allocno classes containing to non-empty set of
- allocatable hard regs. */
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- if (ira_class_hard_regs_num[cl] > 0)
- {
- temp_hard_regset = reg_class_contents[cl] & ~no_unit_alloc_regs;
- set_p = false;
- for (j = 0; j < ira_allocno_classes_num; j++)
- {
- temp_hard_regset2 = (reg_class_contents[ira_allocno_classes[j]]
- & ~no_unit_alloc_regs);
- if ((enum reg_class) cl == ira_allocno_classes[j])
- break;
- else if (hard_reg_set_subset_p (temp_hard_regset,
- temp_hard_regset2))
- set_p = true;
- }
- if (set_p && j >= ira_allocno_classes_num)
- ira_important_classes[ira_important_classes_num++]
- = (enum reg_class) cl;
- }
- /* Now add allocno classes to the important classes. */
- for (j = 0; j < ira_allocno_classes_num; j++)
- ira_important_classes[ira_important_classes_num++]
- = ira_allocno_classes[j];
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- ira_reg_allocno_class_p[cl] = false;
- ira_reg_pressure_class_p[cl] = false;
- }
- for (j = 0; j < ira_allocno_classes_num; j++)
- ira_reg_allocno_class_p[ira_allocno_classes[j]] = true;
- setup_pressure_classes ();
- setup_uniform_class_p ();
-}
-
-/* Setup translation in CLASS_TRANSLATE of all classes into a class
- given by array CLASSES of length CLASSES_NUM. The function is used
- make translation any reg class to an allocno class or to an
- pressure class. This translation is necessary for some
- calculations when we can use only allocno or pressure classes and
- such translation represents an approximate representation of all
- classes.
-
- The translation in case when allocatable hard register set of a
- given class is subset of allocatable hard register set of a class
- in CLASSES is pretty simple. We use smallest classes from CLASSES
- containing a given class. If allocatable hard register set of a
- given class is not a subset of any corresponding set of a class
- from CLASSES, we use the cheapest (with load/store point of view)
- class from CLASSES whose set intersects with given class set. */
-static void
-setup_class_translate_array (enum reg_class *class_translate,
- int classes_num, enum reg_class *classes)
-{
- int cl, mode;
- enum reg_class aclass, best_class, *cl_ptr;
- int i, cost, min_cost, best_cost;
-
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- class_translate[cl] = NO_REGS;
-
- for (i = 0; i < classes_num; i++)
- {
- aclass = classes[i];
- for (cl_ptr = &alloc_reg_class_subclasses[aclass][0];
- (cl = *cl_ptr) != LIM_REG_CLASSES;
- cl_ptr++)
- if (class_translate[cl] == NO_REGS)
- class_translate[cl] = aclass;
- class_translate[aclass] = aclass;
- }
- /* For classes which are not fully covered by one of given classes
- (in other words covered by more one given class), use the
- cheapest class. */
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- if (cl == NO_REGS || class_translate[cl] != NO_REGS)
- continue;
- best_class = NO_REGS;
- best_cost = INT_MAX;
- for (i = 0; i < classes_num; i++)
- {
- aclass = classes[i];
- temp_hard_regset = (reg_class_contents[aclass]
- & reg_class_contents[cl]
- & ~no_unit_alloc_regs);
- if (! hard_reg_set_empty_p (temp_hard_regset))
- {
- min_cost = INT_MAX;
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- cost = (ira_memory_move_cost[mode][aclass][0]
- + ira_memory_move_cost[mode][aclass][1]);
- if (min_cost > cost)
- min_cost = cost;
- }
- if (best_class == NO_REGS || best_cost > min_cost)
- {
- best_class = aclass;
- best_cost = min_cost;
- }
- }
- }
- class_translate[cl] = best_class;
- }
-}
-
-/* Set up array IRA_ALLOCNO_CLASS_TRANSLATE and
- IRA_PRESSURE_CLASS_TRANSLATE. */
-static void
-setup_class_translate (void)
-{
- setup_class_translate_array (ira_allocno_class_translate,
- ira_allocno_classes_num, ira_allocno_classes);
- setup_class_translate_array (ira_pressure_class_translate,
- ira_pressure_classes_num, ira_pressure_classes);
-}
-
-/* Order numbers of allocno classes in original target allocno class
- array, -1 for non-allocno classes. */
-static int allocno_class_order[N_REG_CLASSES];
-
-/* The function used to sort the important classes. */
-static int
-comp_reg_classes_func (const void *v1p, const void *v2p)
-{
- enum reg_class cl1 = *(const enum reg_class *) v1p;
- enum reg_class cl2 = *(const enum reg_class *) v2p;
- enum reg_class tcl1, tcl2;
- int diff;
-
- tcl1 = ira_allocno_class_translate[cl1];
- tcl2 = ira_allocno_class_translate[cl2];
- if (tcl1 != NO_REGS && tcl2 != NO_REGS
- && (diff = allocno_class_order[tcl1] - allocno_class_order[tcl2]) != 0)
- return diff;
- return (int) cl1 - (int) cl2;
-}
-
-/* For correct work of function setup_reg_class_relation we need to
- reorder important classes according to the order of their allocno
- classes. It places important classes containing the same
- allocatable hard register set adjacent to each other and allocno
- class with the allocatable hard register set right after the other
- important classes with the same set.
-
- In example from comments of function
- setup_allocno_and_important_classes, it places LEGACY_REGS and
- GENERAL_REGS close to each other and GENERAL_REGS is after
- LEGACY_REGS. */
-static void
-reorder_important_classes (void)
-{
- int i;
-
- for (i = 0; i < N_REG_CLASSES; i++)
- allocno_class_order[i] = -1;
- for (i = 0; i < ira_allocno_classes_num; i++)
- allocno_class_order[ira_allocno_classes[i]] = i;
- qsort (ira_important_classes, ira_important_classes_num,
- sizeof (enum reg_class), comp_reg_classes_func);
- for (i = 0; i < ira_important_classes_num; i++)
- ira_important_class_nums[ira_important_classes[i]] = i;
-}
-
-/* Set up IRA_REG_CLASS_SUBUNION, IRA_REG_CLASS_SUPERUNION,
- IRA_REG_CLASS_SUPER_CLASSES, IRA_REG_CLASSES_INTERSECT, and
- IRA_REG_CLASSES_INTERSECT_P. For the meaning of the relations,
- please see corresponding comments in ira-int.h. */
-static void
-setup_reg_class_relations (void)
-{
- int i, cl1, cl2, cl3;
- HARD_REG_SET intersection_set, union_set, temp_set2;
- bool important_class_p[N_REG_CLASSES];
-
- memset (important_class_p, 0, sizeof (important_class_p));
- for (i = 0; i < ira_important_classes_num; i++)
- important_class_p[ira_important_classes[i]] = true;
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- {
- ira_reg_class_super_classes[cl1][0] = LIM_REG_CLASSES;
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- ira_reg_classes_intersect_p[cl1][cl2] = false;
- ira_reg_class_intersect[cl1][cl2] = NO_REGS;
- ira_reg_class_subset[cl1][cl2] = NO_REGS;
- temp_hard_regset = reg_class_contents[cl1] & ~no_unit_alloc_regs;
- temp_set2 = reg_class_contents[cl2] & ~no_unit_alloc_regs;
- if (hard_reg_set_empty_p (temp_hard_regset)
- && hard_reg_set_empty_p (temp_set2))
- {
- /* The both classes have no allocatable hard registers
- -- take all class hard registers into account and use
- reg_class_subunion and reg_class_superunion. */
- for (i = 0;; i++)
- {
- cl3 = reg_class_subclasses[cl1][i];
- if (cl3 == LIM_REG_CLASSES)
- break;
- if (reg_class_subset_p (ira_reg_class_intersect[cl1][cl2],
- (enum reg_class) cl3))
- ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
- }
- ira_reg_class_subunion[cl1][cl2] = reg_class_subunion[cl1][cl2];
- ira_reg_class_superunion[cl1][cl2] = reg_class_superunion[cl1][cl2];
- continue;
- }
- ira_reg_classes_intersect_p[cl1][cl2]
- = hard_reg_set_intersect_p (temp_hard_regset, temp_set2);
- if (important_class_p[cl1] && important_class_p[cl2]
- && hard_reg_set_subset_p (temp_hard_regset, temp_set2))
- {
- /* CL1 and CL2 are important classes and CL1 allocatable
- hard register set is inside of CL2 allocatable hard
- registers -- make CL1 a superset of CL2. */
- enum reg_class *p;
-
- p = &ira_reg_class_super_classes[cl1][0];
- while (*p != LIM_REG_CLASSES)
- p++;
- *p++ = (enum reg_class) cl2;
- *p = LIM_REG_CLASSES;
- }
- ira_reg_class_subunion[cl1][cl2] = NO_REGS;
- ira_reg_class_superunion[cl1][cl2] = NO_REGS;
- intersection_set = (reg_class_contents[cl1]
- & reg_class_contents[cl2]
- & ~no_unit_alloc_regs);
- union_set = ((reg_class_contents[cl1] | reg_class_contents[cl2])
- & ~no_unit_alloc_regs);
- for (cl3 = 0; cl3 < N_REG_CLASSES; cl3++)
- {
- temp_hard_regset = reg_class_contents[cl3] & ~no_unit_alloc_regs;
- if (hard_reg_set_subset_p (temp_hard_regset, intersection_set))
- {
- /* CL3 allocatable hard register set is inside of
- intersection of allocatable hard register sets
- of CL1 and CL2. */
- if (important_class_p[cl3])
- {
- temp_set2
- = (reg_class_contents
- [ira_reg_class_intersect[cl1][cl2]]);
- temp_set2 &= ~no_unit_alloc_regs;
- if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- /* If the allocatable hard register sets are
- the same, prefer GENERAL_REGS or the
- smallest class for debugging
- purposes. */
- || (temp_hard_regset == temp_set2
- && (cl3 == GENERAL_REGS
- || ((ira_reg_class_intersect[cl1][cl2]
- != GENERAL_REGS)
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int)
- ira_reg_class_intersect[cl1][cl2]])))))
- ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
- }
- temp_set2
- = (reg_class_contents[ira_reg_class_subset[cl1][cl2]]
- & ~no_unit_alloc_regs);
- if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- /* Ignore unavailable hard registers and prefer
- smallest class for debugging purposes. */
- || (temp_hard_regset == temp_set2
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_subset[cl1][cl2]])))
- ira_reg_class_subset[cl1][cl2] = (enum reg_class) cl3;
- }
- if (important_class_p[cl3]
- && hard_reg_set_subset_p (temp_hard_regset, union_set))
- {
- /* CL3 allocatable hard register set is inside of
- union of allocatable hard register sets of CL1
- and CL2. */
- temp_set2
- = (reg_class_contents[ira_reg_class_subunion[cl1][cl2]]
- & ~no_unit_alloc_regs);
- if (ira_reg_class_subunion[cl1][cl2] == NO_REGS
- || (hard_reg_set_subset_p (temp_set2, temp_hard_regset)
-
- && (temp_set2 != temp_hard_regset
- || cl3 == GENERAL_REGS
- /* If the allocatable hard register sets are the
- same, prefer GENERAL_REGS or the smallest
- class for debugging purposes. */
- || (ira_reg_class_subunion[cl1][cl2] != GENERAL_REGS
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_subunion[cl1][cl2]])))))
- ira_reg_class_subunion[cl1][cl2] = (enum reg_class) cl3;
- }
- if (hard_reg_set_subset_p (union_set, temp_hard_regset))
- {
- /* CL3 allocatable hard register set contains union
- of allocatable hard register sets of CL1 and
- CL2. */
- temp_set2
- = (reg_class_contents[ira_reg_class_superunion[cl1][cl2]]
- & ~no_unit_alloc_regs);
- if (ira_reg_class_superunion[cl1][cl2] == NO_REGS
- || (hard_reg_set_subset_p (temp_hard_regset, temp_set2)
-
- && (temp_set2 != temp_hard_regset
- || cl3 == GENERAL_REGS
- /* If the allocatable hard register sets are the
- same, prefer GENERAL_REGS or the smallest
- class for debugging purposes. */
- || (ira_reg_class_superunion[cl1][cl2] != GENERAL_REGS
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_superunion[cl1][cl2]])))))
- ira_reg_class_superunion[cl1][cl2] = (enum reg_class) cl3;
- }
- }
- }
- }
-}
-
-/* Output all uniform and important classes into file F. */
-static void
-print_uniform_and_important_classes (FILE *f)
-{
- int i, cl;
-
- fprintf (f, "Uniform classes:\n");
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- if (ira_uniform_class_p[cl])
- fprintf (f, " %s", reg_class_names[cl]);
- fprintf (f, "\nImportant classes:\n");
- for (i = 0; i < ira_important_classes_num; i++)
- fprintf (f, " %s", reg_class_names[ira_important_classes[i]]);
- fprintf (f, "\n");
-}
-
-/* Output all possible allocno or pressure classes and their
- translation map into file F. */
-static void
-print_translated_classes (FILE *f, bool pressure_p)
-{
- int classes_num = (pressure_p
- ? ira_pressure_classes_num : ira_allocno_classes_num);
- enum reg_class *classes = (pressure_p
- ? ira_pressure_classes : ira_allocno_classes);
- enum reg_class *class_translate = (pressure_p
- ? ira_pressure_class_translate
- : ira_allocno_class_translate);
- int i;
-
- fprintf (f, "%s classes:\n", pressure_p ? "Pressure" : "Allocno");
- for (i = 0; i < classes_num; i++)
- fprintf (f, " %s", reg_class_names[classes[i]]);
- fprintf (f, "\nClass translation:\n");
- for (i = 0; i < N_REG_CLASSES; i++)
- fprintf (f, " %s -> %s\n", reg_class_names[i],
- reg_class_names[class_translate[i]]);
-}
-
-/* Output all possible allocno and translation classes and the
- translation maps into stderr. */
-void
-ira_debug_allocno_classes (void)
-{
- print_uniform_and_important_classes (stderr);
- print_translated_classes (stderr, false);
- print_translated_classes (stderr, true);
-}
-
-/* Set up different arrays concerning class subsets, allocno and
- important classes. */
-static void
-find_reg_classes (void)
-{
- setup_allocno_and_important_classes ();
- setup_class_translate ();
- reorder_important_classes ();
- setup_reg_class_relations ();
-}
-
-
-
-/* Set up the array above. */
-static void
-setup_hard_regno_aclass (void)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
-#if 1
- ira_hard_regno_allocno_class[i]
- = (TEST_HARD_REG_BIT (no_unit_alloc_regs, i)
- ? NO_REGS
- : ira_allocno_class_translate[REGNO_REG_CLASS (i)]);
-#else
- int j;
- enum reg_class cl;
- ira_hard_regno_allocno_class[i] = NO_REGS;
- for (j = 0; j < ira_allocno_classes_num; j++)
- {
- cl = ira_allocno_classes[j];
- if (ira_class_hard_reg_index[cl][i] >= 0)
- {
- ira_hard_regno_allocno_class[i] = cl;
- break;
- }
- }
-#endif
- }
-}
-
-
-
-/* Form IRA_REG_CLASS_MAX_NREGS and IRA_REG_CLASS_MIN_NREGS maps. */
-static void
-setup_reg_class_nregs (void)
-{
- int i, cl, cl2, m;
-
- for (m = 0; m < MAX_MACHINE_MODE; m++)
- {
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- ira_reg_class_max_nregs[cl][m]
- = ira_reg_class_min_nregs[cl][m]
- = targetm.class_max_nregs ((reg_class_t) cl, (machine_mode) m);
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- for (i = 0;
- (cl2 = alloc_reg_class_subclasses[cl][i]) != LIM_REG_CLASSES;
- i++)
- if (ira_reg_class_min_nregs[cl2][m]
- < ira_reg_class_min_nregs[cl][m])
- ira_reg_class_min_nregs[cl][m] = ira_reg_class_min_nregs[cl2][m];
- }
-}
-
-
-
-/* Set up IRA_PROHIBITED_CLASS_MODE_REGS and IRA_CLASS_SINGLETON.
- This function is called once IRA_CLASS_HARD_REGS has been initialized. */
-static void
-setup_prohibited_class_mode_regs (void)
-{
- int j, k, hard_regno, cl, last_hard_regno, count;
-
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- temp_hard_regset = reg_class_contents[cl] & ~no_unit_alloc_regs;
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- {
- count = 0;
- last_hard_regno = -1;
- CLEAR_HARD_REG_SET (ira_prohibited_class_mode_regs[cl][j]);
- for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
- {
- hard_regno = ira_class_hard_regs[cl][k];
- if (!targetm.hard_regno_mode_ok (hard_regno, (machine_mode) j))
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- else if (in_hard_reg_set_p (temp_hard_regset,
- (machine_mode) j, hard_regno))
- {
- last_hard_regno = hard_regno;
- count++;
- }
- }
- ira_class_singleton[cl][j] = (count == 1 ? last_hard_regno : -1);
- }
- }
-}
-
-/* Clarify IRA_PROHIBITED_CLASS_MODE_REGS by excluding hard registers
- spanning from one register pressure class to another one. It is
- called after defining the pressure classes. */
-static void
-clarify_prohibited_class_mode_regs (void)
-{
- int j, k, hard_regno, cl, pclass, nregs;
-
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- {
- CLEAR_HARD_REG_SET (ira_useful_class_mode_regs[cl][j]);
- for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
- {
- hard_regno = ira_class_hard_regs[cl][k];
- if (TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j], hard_regno))
- continue;
- nregs = hard_regno_nregs (hard_regno, (machine_mode) j);
- if (hard_regno + nregs > FIRST_PSEUDO_REGISTER)
- {
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- continue;
- }
- pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)];
- for (nregs-- ;nregs >= 0; nregs--)
- if (((enum reg_class) pclass
- != ira_pressure_class_translate[REGNO_REG_CLASS
- (hard_regno + nregs)]))
- {
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- break;
- }
- if (!TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno))
- add_to_hard_reg_set (&ira_useful_class_mode_regs[cl][j],
- (machine_mode) j, hard_regno);
- }
- }
-}
-
-/* Allocate and initialize IRA_REGISTER_MOVE_COST, IRA_MAY_MOVE_IN_COST
- and IRA_MAY_MOVE_OUT_COST for MODE. */
-void
-ira_init_register_move_cost (machine_mode mode)
-{
- static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
- bool all_match = true;
- unsigned int i, cl1, cl2;
- HARD_REG_SET ok_regs;
-
- ira_assert (ira_register_move_cost[mode] == NULL
- && ira_may_move_in_cost[mode] == NULL
- && ira_may_move_out_cost[mode] == NULL);
- CLEAR_HARD_REG_SET (ok_regs);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (targetm.hard_regno_mode_ok (i, mode))
- SET_HARD_REG_BIT (ok_regs, i);
-
- /* Note that we might be asked about the move costs of modes that
- cannot be stored in any hard register, for example if an inline
- asm tries to create a register operand with an impossible mode.
- We therefore can't assert have_regs_of_mode[mode] here. */
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- int cost;
- if (!hard_reg_set_intersect_p (ok_regs, reg_class_contents[cl1])
- || !hard_reg_set_intersect_p (ok_regs, reg_class_contents[cl2]))
- {
- if ((ira_reg_class_max_nregs[cl1][mode]
- > ira_class_hard_regs_num[cl1])
- || (ira_reg_class_max_nregs[cl2][mode]
- > ira_class_hard_regs_num[cl2]))
- cost = 65535;
- else
- cost = (ira_memory_move_cost[mode][cl1][0]
- + ira_memory_move_cost[mode][cl2][1]) * 2;
- }
- else
- {
- cost = register_move_cost (mode, (enum reg_class) cl1,
- (enum reg_class) cl2);
- ira_assert (cost < 65535);
- }
- all_match &= (last_move_cost[cl1][cl2] == cost);
- last_move_cost[cl1][cl2] = cost;
- }
- if (all_match && last_mode_for_init_move_cost != -1)
- {
- ira_register_move_cost[mode]
- = ira_register_move_cost[last_mode_for_init_move_cost];
- ira_may_move_in_cost[mode]
- = ira_may_move_in_cost[last_mode_for_init_move_cost];
- ira_may_move_out_cost[mode]
- = ira_may_move_out_cost[last_mode_for_init_move_cost];
- return;
- }
- last_mode_for_init_move_cost = mode;
- ira_register_move_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- ira_may_move_in_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- ira_may_move_out_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- int cost;
- enum reg_class *p1, *p2;
-
- if (last_move_cost[cl1][cl2] == 65535)
- {
- ira_register_move_cost[mode][cl1][cl2] = 65535;
- ira_may_move_in_cost[mode][cl1][cl2] = 65535;
- ira_may_move_out_cost[mode][cl1][cl2] = 65535;
- }
- else
- {
- cost = last_move_cost[cl1][cl2];
-
- for (p2 = &reg_class_subclasses[cl2][0];
- *p2 != LIM_REG_CLASSES; p2++)
- if (ira_class_hard_regs_num[*p2] > 0
- && (ira_reg_class_max_nregs[*p2][mode]
- <= ira_class_hard_regs_num[*p2]))
- cost = MAX (cost, ira_register_move_cost[mode][cl1][*p2]);
-
- for (p1 = &reg_class_subclasses[cl1][0];
- *p1 != LIM_REG_CLASSES; p1++)
- if (ira_class_hard_regs_num[*p1] > 0
- && (ira_reg_class_max_nregs[*p1][mode]
- <= ira_class_hard_regs_num[*p1]))
- cost = MAX (cost, ira_register_move_cost[mode][*p1][cl2]);
-
- ira_assert (cost <= 65535);
- ira_register_move_cost[mode][cl1][cl2] = cost;
-
- if (ira_class_subset_p[cl1][cl2])
- ira_may_move_in_cost[mode][cl1][cl2] = 0;
- else
- ira_may_move_in_cost[mode][cl1][cl2] = cost;
-
- if (ira_class_subset_p[cl2][cl1])
- ira_may_move_out_cost[mode][cl1][cl2] = 0;
- else
- ira_may_move_out_cost[mode][cl1][cl2] = cost;
- }
- }
-}
-
-
-
-/* This is called once during compiler work. It sets up
- different arrays whose values don't depend on the compiled
- function. */
-void
-ira_init_once (void)
-{
- ira_init_costs_once ();
- lra_init_once ();
-
- ira_use_lra_p = targetm.lra_p ();
-}
-
-/* Free ira_max_register_move_cost, ira_may_move_in_cost and
- ira_may_move_out_cost for each mode. */
-void
-target_ira_int::free_register_move_costs (void)
-{
- int mode, i;
-
- /* Reset move_cost and friends, making sure we only free shared
- table entries once. */
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- if (x_ira_register_move_cost[mode])
- {
- for (i = 0;
- i < mode && (x_ira_register_move_cost[i]
- != x_ira_register_move_cost[mode]);
- i++)
- ;
- if (i == mode)
- {
- free (x_ira_register_move_cost[mode]);
- free (x_ira_may_move_in_cost[mode]);
- free (x_ira_may_move_out_cost[mode]);
- }
- }
- memset (x_ira_register_move_cost, 0, sizeof x_ira_register_move_cost);
- memset (x_ira_may_move_in_cost, 0, sizeof x_ira_may_move_in_cost);
- memset (x_ira_may_move_out_cost, 0, sizeof x_ira_may_move_out_cost);
- last_mode_for_init_move_cost = -1;
-}
-
-target_ira_int::~target_ira_int ()
-{
- free_ira_costs ();
- free_register_move_costs ();
-}
-
-/* This is called every time when register related information is
- changed. */
-void
-ira_init (void)
-{
- this_target_ira_int->free_register_move_costs ();
- setup_reg_mode_hard_regset ();
- setup_alloc_regs (flag_omit_frame_pointer != 0);
- setup_class_subset_and_memory_move_costs ();
- setup_reg_class_nregs ();
- setup_prohibited_class_mode_regs ();
- find_reg_classes ();
- clarify_prohibited_class_mode_regs ();
- setup_hard_regno_aclass ();
- ira_init_costs ();
-}
-
-
-#define ira_prohibited_mode_move_regs_initialized_p \
- (this_target_ira_int->x_ira_prohibited_mode_move_regs_initialized_p)
-
-/* Set up IRA_PROHIBITED_MODE_MOVE_REGS. */
-static void
-setup_prohibited_mode_move_regs (void)
-{
- int i, j;
- rtx test_reg1, test_reg2, move_pat;
- rtx_insn *move_insn;
-
- if (ira_prohibited_mode_move_regs_initialized_p)
- return;
- ira_prohibited_mode_move_regs_initialized_p = true;
- test_reg1 = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
- test_reg2 = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
- move_pat = gen_rtx_SET (test_reg1, test_reg2);
- move_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, move_pat, 0, -1, 0);
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- {
- SET_HARD_REG_SET (ira_prohibited_mode_move_regs[i]);
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- {
- if (!targetm.hard_regno_mode_ok (j, (machine_mode) i))
- continue;
- set_mode_and_regno (test_reg1, (machine_mode) i, j);
- set_mode_and_regno (test_reg2, (machine_mode) i, j);
- INSN_CODE (move_insn) = -1;
- recog_memoized (move_insn);
- if (INSN_CODE (move_insn) < 0)
- continue;
- extract_insn (move_insn);
- /* We don't know whether the move will be in code that is optimized
- for size or speed, so consider all enabled alternatives. */
- if (! constrain_operands (1, get_enabled_alternatives (move_insn)))
- continue;
- CLEAR_HARD_REG_BIT (ira_prohibited_mode_move_regs[i], j);
- }
- }
-}
-
-
-
-/* Extract INSN and return the set of alternatives that we should consider.
- This excludes any alternatives whose constraints are obviously impossible
- to meet (e.g. because the constraint requires a constant and the operand
- is nonconstant). It also excludes alternatives that are bound to need
- a spill or reload, as long as we have other alternatives that match
- exactly. */
-alternative_mask
-ira_setup_alts (rtx_insn *insn)
-{
- int nop, nalt;
- bool curr_swapped;
- const char *p;
- int commutative = -1;
-
- extract_insn (insn);
- preprocess_constraints (insn);
- alternative_mask preferred = get_preferred_alternatives (insn);
- alternative_mask alts = 0;
- alternative_mask exact_alts = 0;
- /* Check that the hard reg set is enough for holding all
- alternatives. It is hard to imagine the situation when the
- assertion is wrong. */
- ira_assert (recog_data.n_alternatives
- <= (int) MAX (sizeof (HARD_REG_ELT_TYPE) * CHAR_BIT,
- FIRST_PSEUDO_REGISTER));
- for (nop = 0; nop < recog_data.n_operands; nop++)
- if (recog_data.constraints[nop][0] == '%')
- {
- commutative = nop;
- break;
- }
- for (curr_swapped = false;; curr_swapped = true)
- {
- for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
- {
- if (!TEST_BIT (preferred, nalt) || TEST_BIT (exact_alts, nalt))
- continue;
-
- const operand_alternative *op_alt
- = &recog_op_alt[nalt * recog_data.n_operands];
- int this_reject = 0;
- for (nop = 0; nop < recog_data.n_operands; nop++)
- {
- int c, len;
-
- this_reject += op_alt[nop].reject;
-
- rtx op = recog_data.operand[nop];
- p = op_alt[nop].constraint;
- if (*p == 0 || *p == ',')
- continue;
-
- bool win_p = false;
- do
- switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
- {
- case '#':
- case ',':
- c = '\0';
- /* FALLTHRU */
- case '\0':
- len = 0;
- break;
-
- case '%':
- /* The commutative modifier is handled above. */
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- char *end;
- unsigned long dup = strtoul (p, &end, 10);
- rtx other = recog_data.operand[dup];
- len = end - p;
- if (MEM_P (other)
- ? rtx_equal_p (other, op)
- : REG_P (op) || SUBREG_P (op))
- goto op_success;
- win_p = true;
- }
- break;
-
- case 'g':
- goto op_success;
- break;
-
- default:
- {
- enum constraint_num cn = lookup_constraint (p);
- rtx mem = NULL;
- switch (get_constraint_type (cn))
- {
- case CT_REGISTER:
- if (reg_class_for_constraint (cn) != NO_REGS)
- {
- if (REG_P (op) || SUBREG_P (op))
- goto op_success;
- win_p = true;
- }
- break;
-
- case CT_CONST_INT:
- if (CONST_INT_P (op)
- && (insn_const_int_ok_for_constraint
- (INTVAL (op), cn)))
- goto op_success;
- break;
-
- case CT_ADDRESS:
- goto op_success;
-
- case CT_MEMORY:
- case CT_RELAXED_MEMORY:
- mem = op;
- /* Fall through. */
- case CT_SPECIAL_MEMORY:
- if (!mem)
- mem = extract_mem_from_operand (op);
- if (MEM_P (mem))
- goto op_success;
- win_p = true;
- break;
-
- case CT_FIXED_FORM:
- if (constraint_satisfied_p (op, cn))
- goto op_success;
- break;
- }
- break;
- }
- }
- while (p += len, c);
- if (!win_p)
- break;
- /* We can make the alternative match by spilling a register
- to memory or loading something into a register. Count a
- cost of one reload (the equivalent of the '?' constraint). */
- this_reject += 6;
- op_success:
- ;
- }
-
- if (nop >= recog_data.n_operands)
- {
- alts |= ALTERNATIVE_BIT (nalt);
- if (this_reject == 0)
- exact_alts |= ALTERNATIVE_BIT (nalt);
- }
- }
- if (commutative < 0)
- break;
- /* Swap forth and back to avoid changing recog_data. */
- std::swap (recog_data.operand[commutative],
- recog_data.operand[commutative + 1]);
- if (curr_swapped)
- break;
- }
- return exact_alts ? exact_alts : alts;
-}
-
-/* Return the number of the output non-early clobber operand which
- should be the same in any case as operand with number OP_NUM (or
- negative value if there is no such operand). ALTS is the mask
- of alternatives that we should consider. SINGLE_INPUT_OP_HAS_CSTR_P
- should be set in this function, it indicates whether there is only
- a single input operand which has the matching constraint on the
- output operand at the position specified in return value. If the
- pattern allows any one of several input operands holds the matching
- constraint, it's set as false, one typical case is destructive FMA
- instruction on target rs6000. Note that for a non-NO_REG preferred
- register class with no free register move copy, if the parameter
- PARAM_IRA_CONSIDER_DUP_IN_ALL_ALTS is set to one, this function
- will check all available alternatives for matching constraints,
- even if it has found or will find one alternative with non-NO_REG
- regclass, it can respect more cases with matching constraints. If
- PARAM_IRA_CONSIDER_DUP_IN_ALL_ALTS is set to zero,
- SINGLE_INPUT_OP_HAS_CSTR_P is always true, it will stop to find
- matching constraint relationship once it hits some alternative with
- some non-NO_REG regclass. */
-int
-ira_get_dup_out_num (int op_num, alternative_mask alts,
- bool &single_input_op_has_cstr_p)
-{
- int curr_alt, c, original;
- bool ignore_p, use_commut_op_p;
- const char *str;
-
- if (op_num < 0 || recog_data.n_alternatives == 0)
- return -1;
- /* We should find duplications only for input operands. */
- if (recog_data.operand_type[op_num] != OP_IN)
- return -1;
- str = recog_data.constraints[op_num];
- use_commut_op_p = false;
- single_input_op_has_cstr_p = true;
-
- rtx op = recog_data.operand[op_num];
- int op_regno = reg_or_subregno (op);
- enum reg_class op_pref_cl = reg_preferred_class (op_regno);
- machine_mode op_mode = GET_MODE (op);
-
- ira_init_register_move_cost_if_necessary (op_mode);
- /* If the preferred regclass isn't NO_REG, continue to find the matching
- constraint in all available alternatives with preferred regclass, even
- if we have found or will find one alternative whose constraint stands
- for a REG (non-NO_REG) regclass. Note that it would be fine not to
- respect matching constraint if the register copy is free, so exclude
- it. */
- bool respect_dup_despite_reg_cstr
- = param_ira_consider_dup_in_all_alts
- && op_pref_cl != NO_REGS
- && ira_register_move_cost[op_mode][op_pref_cl][op_pref_cl] > 0;
-
- /* Record the alternative whose constraint uses the same regclass as the
- preferred regclass, later if we find one matching constraint for this
- operand with preferred reclass, we will visit these recorded
- alternatives to check whether if there is one alternative in which no
- any INPUT operands have one matching constraint same as our candidate.
- If yes, it means there is one alternative which is perfectly fine
- without satisfying this matching constraint. If no, it means in any
- alternatives there is one other INPUT operand holding this matching
- constraint, it's fine to respect this matching constraint and further
- create this constraint copy since it would become harmless once some
- other takes preference and it's interfered. */
- alternative_mask pref_cl_alts;
-
- for (;;)
- {
- pref_cl_alts = 0;
-
- for (curr_alt = 0, ignore_p = !TEST_BIT (alts, curr_alt),
- original = -1;;)
- {
- c = *str;
- if (c == '\0')
- break;
- if (c == '#')
- ignore_p = true;
- else if (c == ',')
- {
- curr_alt++;
- ignore_p = !TEST_BIT (alts, curr_alt);
- }
- else if (! ignore_p)
- switch (c)
- {
- case 'g':
- goto fail;
- default:
- {
- enum constraint_num cn = lookup_constraint (str);
- enum reg_class cl = reg_class_for_constraint (cn);
- if (cl != NO_REGS && !targetm.class_likely_spilled_p (cl))
- {
- if (respect_dup_despite_reg_cstr)
- {
- /* If it's free to move from one preferred class to
- the one without matching constraint, it doesn't
- have to respect this constraint with costs. */
- if (cl != op_pref_cl
- && (ira_reg_class_intersect[cl][op_pref_cl]
- != NO_REGS)
- && (ira_may_move_in_cost[op_mode][op_pref_cl][cl]
- == 0))
- goto fail;
- else if (cl == op_pref_cl)
- pref_cl_alts |= ALTERNATIVE_BIT (curr_alt);
- }
- else
- goto fail;
- }
- if (constraint_satisfied_p (op, cn))
- goto fail;
- break;
- }
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- char *end;
- int n = (int) strtoul (str, &end, 10);
- str = end;
- if (original != -1 && original != n)
- goto fail;
- gcc_assert (n < recog_data.n_operands);
- if (respect_dup_despite_reg_cstr)
- {
- const operand_alternative *op_alt
- = &recog_op_alt[curr_alt * recog_data.n_operands];
- /* Only respect the one with preferred rclass, without
- respect_dup_despite_reg_cstr it's possible to get
- one whose regclass isn't preferred first before,
- but it would fail since there should be other
- alternatives with preferred regclass. */
- if (op_alt[n].cl == op_pref_cl)
- original = n;
- }
- else
- original = n;
- continue;
- }
- }
- str += CONSTRAINT_LEN (c, str);
- }
- if (original == -1)
- goto fail;
- if (recog_data.operand_type[original] == OP_OUT)
- {
- if (pref_cl_alts == 0)
- return original;
- /* Visit these recorded alternatives to check whether
- there is one alternative in which no any INPUT operands
- have one matching constraint same as our candidate.
- Give up this candidate if so. */
- int nop, nalt;
- for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
- {
- if (!TEST_BIT (pref_cl_alts, nalt))
- continue;
- const operand_alternative *op_alt
- = &recog_op_alt[nalt * recog_data.n_operands];
- bool dup_in_other = false;
- for (nop = 0; nop < recog_data.n_operands; nop++)
- {
- if (recog_data.operand_type[nop] != OP_IN)
- continue;
- if (nop == op_num)
- continue;
- if (op_alt[nop].matches == original)
- {
- dup_in_other = true;
- break;
- }
- }
- if (!dup_in_other)
- return -1;
- }
- single_input_op_has_cstr_p = false;
- return original;
- }
- fail:
- if (use_commut_op_p)
- break;
- use_commut_op_p = true;
- if (recog_data.constraints[op_num][0] == '%')
- str = recog_data.constraints[op_num + 1];
- else if (op_num > 0 && recog_data.constraints[op_num - 1][0] == '%')
- str = recog_data.constraints[op_num - 1];
- else
- break;
- }
- return -1;
-}
-
-
-
-/* Search forward to see if the source register of a copy insn dies
- before either it or the destination register is modified, but don't
- scan past the end of the basic block. If so, we can replace the
- source with the destination and let the source die in the copy
- insn.
-
- This will reduce the number of registers live in that range and may
- enable the destination and the source coalescing, thus often saving
- one register in addition to a register-register copy. */
-
-static void
-decrease_live_ranges_number (void)
-{
- basic_block bb;
- rtx_insn *insn;
- rtx set, src, dest, dest_death, note;
- rtx_insn *p, *q;
- int sregno, dregno;
-
- if (! flag_expensive_optimizations)
- return;
-
- if (ira_dump_file)
- fprintf (ira_dump_file, "Starting decreasing number of live ranges...\n");
-
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- {
- set = single_set (insn);
- if (! set)
- continue;
- src = SET_SRC (set);
- dest = SET_DEST (set);
- if (! REG_P (src) || ! REG_P (dest)
- || find_reg_note (insn, REG_DEAD, src))
- continue;
- sregno = REGNO (src);
- dregno = REGNO (dest);
-
- /* We don't want to mess with hard regs if register classes
- are small. */
- if (sregno == dregno
- || (targetm.small_register_classes_for_mode_p (GET_MODE (src))
- && (sregno < FIRST_PSEUDO_REGISTER
- || dregno < FIRST_PSEUDO_REGISTER))
- /* We don't see all updates to SP if they are in an
- auto-inc memory reference, so we must disallow this
- optimization on them. */
- || sregno == STACK_POINTER_REGNUM
- || dregno == STACK_POINTER_REGNUM)
- continue;
-
- dest_death = NULL_RTX;
-
- for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
- {
- if (! INSN_P (p))
- continue;
- if (BLOCK_FOR_INSN (p) != bb)
- break;
-
- if (reg_set_p (src, p) || reg_set_p (dest, p)
- /* If SRC is an asm-declared register, it must not be
- replaced in any asm. Unfortunately, the REG_EXPR
- tree for the asm variable may be absent in the SRC
- rtx, so we can't check the actual register
- declaration easily (the asm operand will have it,
- though). To avoid complicating the test for a rare
- case, we just don't perform register replacement
- for a hard reg mentioned in an asm. */
- || (sregno < FIRST_PSEUDO_REGISTER
- && asm_noperands (PATTERN (p)) >= 0
- && reg_overlap_mentioned_p (src, PATTERN (p)))
- /* Don't change hard registers used by a call. */
- || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER
- && find_reg_fusage (p, USE, src))
- /* Don't change a USE of a register. */
- || (GET_CODE (PATTERN (p)) == USE
- && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
- break;
-
- /* See if all of SRC dies in P. This test is slightly
- more conservative than it needs to be. */
- if ((note = find_regno_note (p, REG_DEAD, sregno))
- && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
- {
- int failed = 0;
-
- /* We can do the optimization. Scan forward from INSN
- again, replacing regs as we go. Set FAILED if a
- replacement can't be done. In that case, we can't
- move the death note for SRC. This should be
- rare. */
-
- /* Set to stop at next insn. */
- for (q = next_real_insn (insn);
- q != next_real_insn (p);
- q = next_real_insn (q))
- {
- if (reg_overlap_mentioned_p (src, PATTERN (q)))
- {
- /* If SRC is a hard register, we might miss
- some overlapping registers with
- validate_replace_rtx, so we would have to
- undo it. We can't if DEST is present in
- the insn, so fail in that combination of
- cases. */
- if (sregno < FIRST_PSEUDO_REGISTER
- && reg_mentioned_p (dest, PATTERN (q)))
- failed = 1;
-
- /* Attempt to replace all uses. */
- else if (!validate_replace_rtx (src, dest, q))
- failed = 1;
-
- /* If this succeeded, but some part of the
- register is still present, undo the
- replacement. */
- else if (sregno < FIRST_PSEUDO_REGISTER
- && reg_overlap_mentioned_p (src, PATTERN (q)))
- {
- validate_replace_rtx (dest, src, q);
- failed = 1;
- }
- }
-
- /* If DEST dies here, remove the death note and
- save it for later. Make sure ALL of DEST dies
- here; again, this is overly conservative. */
- if (! dest_death
- && (dest_death = find_regno_note (q, REG_DEAD, dregno)))
- {
- if (GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))
- remove_note (q, dest_death);
- else
- {
- failed = 1;
- dest_death = 0;
- }
- }
- }
-
- if (! failed)
- {
- /* Move death note of SRC from P to INSN. */
- remove_note (p, note);
- XEXP (note, 1) = REG_NOTES (insn);
- REG_NOTES (insn) = note;
- }
-
- /* DEST is also dead if INSN has a REG_UNUSED note for
- DEST. */
- if (! dest_death
- && (dest_death
- = find_regno_note (insn, REG_UNUSED, dregno)))
- {
- PUT_REG_NOTE_KIND (dest_death, REG_DEAD);
- remove_note (insn, dest_death);
- }
-
- /* Put death note of DEST on P if we saw it die. */
- if (dest_death)
- {
- XEXP (dest_death, 1) = REG_NOTES (p);
- REG_NOTES (p) = dest_death;
- }
- break;
- }
-
- /* If SRC is a hard register which is set or killed in
- some other way, we can't do this optimization. */
- else if (sregno < FIRST_PSEUDO_REGISTER && dead_or_set_p (p, src))
- break;
- }
- }
-}
-
-
-
-/* Return nonzero if REGNO is a particularly bad choice for reloading X. */
-static bool
-ira_bad_reload_regno_1 (int regno, rtx x)
-{
- int x_regno, n, i;
- ira_allocno_t a;
- enum reg_class pref;
-
- /* We only deal with pseudo regs. */
- if (! x || GET_CODE (x) != REG)
- return false;
-
- x_regno = REGNO (x);
- if (x_regno < FIRST_PSEUDO_REGISTER)
- return false;
-
- /* If the pseudo prefers REGNO explicitly, then do not consider
- REGNO a bad spill choice. */
- pref = reg_preferred_class (x_regno);
- if (reg_class_size[pref] == 1)
- return !TEST_HARD_REG_BIT (reg_class_contents[pref], regno);
-
- /* If the pseudo conflicts with REGNO, then we consider REGNO a
- poor choice for a reload regno. */
- a = ira_regno_allocno_map[x_regno];
- n = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < n; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
- if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno))
- return true;
- }
- return false;
-}
-
-/* Return nonzero if REGNO is a particularly bad choice for reloading
- IN or OUT. */
-bool
-ira_bad_reload_regno (int regno, rtx in, rtx out)
-{
- return (ira_bad_reload_regno_1 (regno, in)
- || ira_bad_reload_regno_1 (regno, out));
-}
-
-/* Add register clobbers from asm statements. */
-static void
-compute_regs_asm_clobbered (void)
-{
- basic_block bb;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- df_ref def;
-
- if (NONDEBUG_INSN_P (insn) && asm_noperands (PATTERN (insn)) >= 0)
- FOR_EACH_INSN_DEF (def, insn)
- {
- unsigned int dregno = DF_REF_REGNO (def);
- if (HARD_REGISTER_NUM_P (dregno))
- add_to_hard_reg_set (&crtl->asm_clobbers,
- GET_MODE (DF_REF_REAL_REG (def)),
- dregno);
- }
- }
- }
-}
-
-
-/* Set up ELIMINABLE_REGSET, IRA_NO_ALLOC_REGS, and
- REGS_EVER_LIVE. */
-void
-ira_setup_eliminable_regset (void)
-{
- int i;
- static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
- int fp_reg_count = hard_regno_nregs (HARD_FRAME_POINTER_REGNUM, Pmode);
-
- /* Setup is_leaf as frame_pointer_required may use it. This function
- is called by sched_init before ira if scheduling is enabled. */
- crtl->is_leaf = leaf_function_p ();
-
- /* FIXME: If EXIT_IGNORE_STACK is set, we will not save and restore
- sp for alloca. So we can't eliminate the frame pointer in that
- case. At some point, we should improve this by emitting the
- sp-adjusting insns for this case. */
- frame_pointer_needed
- = (! flag_omit_frame_pointer
- || (cfun->calls_alloca && EXIT_IGNORE_STACK)
- /* We need the frame pointer to catch stack overflow exceptions if
- the stack pointer is moving (as for the alloca case just above). */
- || (STACK_CHECK_MOVING_SP
- && flag_stack_check
- && flag_exceptions
- && cfun->can_throw_non_call_exceptions)
- || crtl->accesses_prior_frames
- || (SUPPORTS_STACK_ALIGNMENT && crtl->stack_realign_needed)
- || targetm.frame_pointer_required ());
-
- /* The chance that FRAME_POINTER_NEEDED is changed from inspecting
- RTL is very small. So if we use frame pointer for RA and RTL
- actually prevents this, we will spill pseudos assigned to the
- frame pointer in LRA. */
-
- if (frame_pointer_needed)
- for (i = 0; i < fp_reg_count; i++)
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM + i, true);
-
- ira_no_alloc_regs = no_unit_alloc_regs;
- CLEAR_HARD_REG_SET (eliminable_regset);
-
- compute_regs_asm_clobbered ();
-
- /* Build the regset of all eliminable registers and show we can't
- use those that we already know won't be eliminated. */
- for (i = 0; i < (int) ARRAY_SIZE (eliminables); i++)
- {
- bool cannot_elim
- = (! targetm.can_eliminate (eliminables[i].from, eliminables[i].to)
- || (eliminables[i].to == STACK_POINTER_REGNUM && frame_pointer_needed));
-
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, eliminables[i].from))
- {
- SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
-
- if (cannot_elim)
- SET_HARD_REG_BIT (ira_no_alloc_regs, eliminables[i].from);
- }
- else if (cannot_elim)
- error ("%s cannot be used in %<asm%> here",
- reg_names[eliminables[i].from]);
- else
- df_set_regs_ever_live (eliminables[i].from, true);
- }
- if (!HARD_FRAME_POINTER_IS_FRAME_POINTER)
- {
- for (i = 0; i < fp_reg_count; i++)
- if (global_regs[HARD_FRAME_POINTER_REGNUM + i])
- /* Nothing to do: the register is already treated as live
- where appropriate, and cannot be eliminated. */
- ;
- else if (!TEST_HARD_REG_BIT (crtl->asm_clobbers,
- HARD_FRAME_POINTER_REGNUM + i))
- {
- SET_HARD_REG_BIT (eliminable_regset,
- HARD_FRAME_POINTER_REGNUM + i);
- if (frame_pointer_needed)
- SET_HARD_REG_BIT (ira_no_alloc_regs,
- HARD_FRAME_POINTER_REGNUM + i);
- }
- else if (frame_pointer_needed)
- error ("%s cannot be used in %<asm%> here",
- reg_names[HARD_FRAME_POINTER_REGNUM + i]);
- else
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM + i, true);
- }
-}
-
-
-
-/* Vector of substitutions of register numbers,
- used to map pseudo regs into hardware regs.
- This is set up as a result of register allocation.
- Element N is the hard reg assigned to pseudo reg N,
- or is -1 if no hard reg was assigned.
- If N is a hard reg number, element N is N. */
-short *reg_renumber;
-
-/* Set up REG_RENUMBER and CALLER_SAVE_NEEDED (used by reload) from
- the allocation found by IRA. */
-static void
-setup_reg_renumber (void)
-{
- int regno, hard_regno;
- ira_allocno_t a;
- ira_allocno_iterator ai;
-
- caller_save_needed = 0;
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (ira_use_lra_p && ALLOCNO_CAP_MEMBER (a) != NULL)
- continue;
- /* There are no caps at this point. */
- ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
- if (! ALLOCNO_ASSIGNED_P (a))
- /* It can happen if A is not referenced but partially anticipated
- somewhere in a region. */
- ALLOCNO_ASSIGNED_P (a) = true;
- ira_free_allocno_updated_costs (a);
- hard_regno = ALLOCNO_HARD_REGNO (a);
- regno = ALLOCNO_REGNO (a);
- reg_renumber[regno] = (hard_regno < 0 ? -1 : hard_regno);
- if (hard_regno >= 0)
- {
- int i, nwords;
- enum reg_class pclass;
- ira_object_t obj;
-
- pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)];
- nwords = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < nwords; i++)
- {
- obj = ALLOCNO_OBJECT (a, i);
- OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)
- |= ~reg_class_contents[pclass];
- }
- if (ira_need_caller_save_p (a, hard_regno))
- {
- ira_assert (!optimize || flag_caller_saves
- || (ALLOCNO_CALLS_CROSSED_NUM (a)
- == ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
- || regno >= ira_reg_equiv_len
- || ira_equiv_no_lvalue_p (regno));
- caller_save_needed = 1;
- }
- }
- }
-}
-
-/* Set up allocno assignment flags for further allocation
- improvements. */
-static void
-setup_allocno_assignment_flags (void)
-{
- int hard_regno;
- ira_allocno_t a;
- ira_allocno_iterator ai;
-
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (! ALLOCNO_ASSIGNED_P (a))
- /* It can happen if A is not referenced but partially anticipated
- somewhere in a region. */
- ira_free_allocno_updated_costs (a);
- hard_regno = ALLOCNO_HARD_REGNO (a);
- /* Don't assign hard registers to allocnos which are destination
- of removed store at the end of loop. It has no sense to keep
- the same value in different hard registers. It is also
- impossible to assign hard registers correctly to such
- allocnos because the cost info and info about intersected
- calls are incorrect for them. */
- ALLOCNO_ASSIGNED_P (a) = (hard_regno >= 0
- || ALLOCNO_EMIT_DATA (a)->mem_optimized_dest_p
- || (ALLOCNO_MEMORY_COST (a)
- - ALLOCNO_CLASS_COST (a)) < 0);
- ira_assert
- (hard_regno < 0
- || ira_hard_reg_in_set_p (hard_regno, ALLOCNO_MODE (a),
- reg_class_contents[ALLOCNO_CLASS (a)]));
- }
-}
-
-/* Evaluate overall allocation cost and the costs for using hard
- registers and memory for allocnos. */
-static void
-calculate_allocation_cost (void)
-{
- int hard_regno, cost;
- ira_allocno_t a;
- ira_allocno_iterator ai;
-
- ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
- FOR_EACH_ALLOCNO (a, ai)
- {
- hard_regno = ALLOCNO_HARD_REGNO (a);
- ira_assert (hard_regno < 0
- || (ira_hard_reg_in_set_p
- (hard_regno, ALLOCNO_MODE (a),
- reg_class_contents[ALLOCNO_CLASS (a)])));
- if (hard_regno < 0)
- {
- cost = ALLOCNO_MEMORY_COST (a);
- ira_mem_cost += cost;
- }
- else if (ALLOCNO_HARD_REG_COSTS (a) != NULL)
- {
- cost = (ALLOCNO_HARD_REG_COSTS (a)
- [ira_class_hard_reg_index
- [ALLOCNO_CLASS (a)][hard_regno]]);
- ira_reg_cost += cost;
- }
- else
- {
- cost = ALLOCNO_CLASS_COST (a);
- ira_reg_cost += cost;
- }
- ira_overall_cost += cost;
- }
-
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- {
- fprintf (ira_dump_file,
- "+++Costs: overall %" PRId64
- ", reg %" PRId64
- ", mem %" PRId64
- ", ld %" PRId64
- ", st %" PRId64
- ", move %" PRId64,
- ira_overall_cost, ira_reg_cost, ira_mem_cost,
- ira_load_cost, ira_store_cost, ira_shuffle_cost);
- fprintf (ira_dump_file, "\n+++ move loops %d, new jumps %d\n",
- ira_move_loops_num, ira_additional_jumps_num);
- }
-
-}
-
-#ifdef ENABLE_IRA_CHECKING
-/* Check the correctness of the allocation. We do need this because
- of complicated code to transform more one region internal
- representation into one region representation. */
-static void
-check_allocation (void)
-{
- ira_allocno_t a;
- int hard_regno, nregs, conflict_nregs;
- ira_allocno_iterator ai;
-
- FOR_EACH_ALLOCNO (a, ai)
- {
- int n = ALLOCNO_NUM_OBJECTS (a);
- int i;
-
- if (ALLOCNO_CAP_MEMBER (a) != NULL
- || (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
- continue;
- nregs = hard_regno_nregs (hard_regno, ALLOCNO_MODE (a));
- if (nregs == 1)
- /* We allocated a single hard register. */
- n = 1;
- else if (n > 1)
- /* We allocated multiple hard registers, and we will test
- conflicts in a granularity of single hard regs. */
- nregs = 1;
-
- for (i = 0; i < n; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
- ira_object_t conflict_obj;
- ira_object_conflict_iterator oci;
- int this_regno = hard_regno;
- if (n > 1)
- {
- if (REG_WORDS_BIG_ENDIAN)
- this_regno += n - i - 1;
- else
- this_regno += i;
- }
- FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
- {
- ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
- int conflict_hard_regno = ALLOCNO_HARD_REGNO (conflict_a);
- if (conflict_hard_regno < 0)
- continue;
- if (ira_soft_conflict (a, conflict_a))
- continue;
-
- conflict_nregs = hard_regno_nregs (conflict_hard_regno,
- ALLOCNO_MODE (conflict_a));
-
- if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1
- && conflict_nregs == ALLOCNO_NUM_OBJECTS (conflict_a))
- {
- if (REG_WORDS_BIG_ENDIAN)
- conflict_hard_regno += (ALLOCNO_NUM_OBJECTS (conflict_a)
- - OBJECT_SUBWORD (conflict_obj) - 1);
- else
- conflict_hard_regno += OBJECT_SUBWORD (conflict_obj);
- conflict_nregs = 1;
- }
-
- if ((conflict_hard_regno <= this_regno
- && this_regno < conflict_hard_regno + conflict_nregs)
- || (this_regno <= conflict_hard_regno
- && conflict_hard_regno < this_regno + nregs))
- {
- fprintf (stderr, "bad allocation for %d and %d\n",
- ALLOCNO_REGNO (a), ALLOCNO_REGNO (conflict_a));
- gcc_unreachable ();
- }
- }
- }
- }
-}
-#endif
-
-/* Allocate REG_EQUIV_INIT. Set up it from IRA_REG_EQUIV which should
- be already calculated. */
-static void
-setup_reg_equiv_init (void)
-{
- int i;
- int max_regno = max_reg_num ();
-
- for (i = 0; i < max_regno; i++)
- reg_equiv_init (i) = ira_reg_equiv[i].init_insns;
-}
-
-/* Update equiv regno from movement of FROM_REGNO to TO_REGNO. INSNS
- are insns which were generated for such movement. It is assumed
- that FROM_REGNO and TO_REGNO always have the same value at the
- point of any move containing such registers. This function is used
- to update equiv info for register shuffles on the region borders
- and for caller save/restore insns. */
-void
-ira_update_equiv_info_by_shuffle_insn (int to_regno, int from_regno, rtx_insn *insns)
-{
- rtx_insn *insn;
- rtx x, note;
-
- if (! ira_reg_equiv[from_regno].defined_p
- && (! ira_reg_equiv[to_regno].defined_p
- || ((x = ira_reg_equiv[to_regno].memory) != NULL_RTX
- && ! MEM_READONLY_P (x))))
- return;
- insn = insns;
- if (NEXT_INSN (insn) != NULL_RTX)
- {
- if (! ira_reg_equiv[to_regno].defined_p)
- {
- ira_assert (ira_reg_equiv[to_regno].init_insns == NULL_RTX);
- return;
- }
- ira_reg_equiv[to_regno].defined_p = false;
- ira_reg_equiv[to_regno].memory
- = ira_reg_equiv[to_regno].constant
- = ira_reg_equiv[to_regno].invariant
- = ira_reg_equiv[to_regno].init_insns = NULL;
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Invalidating equiv info for reg %d\n", to_regno);
- return;
- }
- /* It is possible that FROM_REGNO still has no equivalence because
- in shuffles to_regno<-from_regno and from_regno<-to_regno the 2nd
- insn was not processed yet. */
- if (ira_reg_equiv[from_regno].defined_p)
- {
- ira_reg_equiv[to_regno].defined_p = true;
- if ((x = ira_reg_equiv[from_regno].memory) != NULL_RTX)
- {
- ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX
- && ira_reg_equiv[from_regno].constant == NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].memory == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].memory, x));
- ira_reg_equiv[to_regno].memory = x;
- if (! MEM_READONLY_P (x))
- /* We don't add the insn to insn init list because memory
- equivalence is just to say what memory is better to use
- when the pseudo is spilled. */
- return;
- }
- else if ((x = ira_reg_equiv[from_regno].constant) != NULL_RTX)
- {
- ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].constant == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].constant, x));
- ira_reg_equiv[to_regno].constant = x;
- }
- else
- {
- x = ira_reg_equiv[from_regno].invariant;
- ira_assert (x != NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].invariant == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].invariant, x));
- ira_reg_equiv[to_regno].invariant = x;
- }
- if (find_reg_note (insn, REG_EQUIV, x) == NULL_RTX)
- {
- note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (x));
- gcc_assert (note != NULL_RTX);
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- {
- fprintf (ira_dump_file,
- " Adding equiv note to insn %u for reg %d ",
- INSN_UID (insn), to_regno);
- dump_value_slim (ira_dump_file, x, 1);
- fprintf (ira_dump_file, "\n");
- }
- }
- }
- ira_reg_equiv[to_regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[to_regno].init_insns);
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Adding equiv init move insn %u to reg %d\n",
- INSN_UID (insn), to_regno);
-}
-
-/* Fix values of array REG_EQUIV_INIT after live range splitting done
- by IRA. */
-static void
-fix_reg_equiv_init (void)
-{
- int max_regno = max_reg_num ();
- int i, new_regno, max;
- rtx set;
- rtx_insn_list *x, *next, *prev;
- rtx_insn *insn;
-
- if (max_regno_before_ira < max_regno)
- {
- max = vec_safe_length (reg_equivs);
- grow_reg_equivs ();
- for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
- for (prev = NULL, x = reg_equiv_init (i);
- x != NULL_RTX;
- x = next)
- {
- next = x->next ();
- insn = x->insn ();
- set = single_set (insn);
- ira_assert (set != NULL_RTX
- && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))));
- if (REG_P (SET_DEST (set))
- && ((int) REGNO (SET_DEST (set)) == i
- || (int) ORIGINAL_REGNO (SET_DEST (set)) == i))
- new_regno = REGNO (SET_DEST (set));
- else if (REG_P (SET_SRC (set))
- && ((int) REGNO (SET_SRC (set)) == i
- || (int) ORIGINAL_REGNO (SET_SRC (set)) == i))
- new_regno = REGNO (SET_SRC (set));
- else
- gcc_unreachable ();
- if (new_regno == i)
- prev = x;
- else
- {
- /* Remove the wrong list element. */
- if (prev == NULL_RTX)
- reg_equiv_init (i) = next;
- else
- XEXP (prev, 1) = next;
- XEXP (x, 1) = reg_equiv_init (new_regno);
- reg_equiv_init (new_regno) = x;
- }
- }
- }
-}
-
-#ifdef ENABLE_IRA_CHECKING
-/* Print redundant memory-memory copies. */
-static void
-print_redundant_copies (void)
-{
- int hard_regno;
- ira_allocno_t a;
- ira_copy_t cp, next_cp;
- ira_allocno_iterator ai;
-
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (ALLOCNO_CAP_MEMBER (a) != NULL)
- /* It is a cap. */
- continue;
- hard_regno = ALLOCNO_HARD_REGNO (a);
- if (hard_regno >= 0)
- continue;
- for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
- if (cp->first == a)
- next_cp = cp->next_first_allocno_copy;
- else
- {
- next_cp = cp->next_second_allocno_copy;
- if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL
- && cp->insn != NULL_RTX
- && ALLOCNO_HARD_REGNO (cp->first) == hard_regno)
- fprintf (ira_dump_file,
- " Redundant move from %d(freq %d):%d\n",
- INSN_UID (cp->insn), cp->freq, hard_regno);
- }
- }
-}
-#endif
-
-/* Setup preferred and alternative classes for new pseudo-registers
- created by IRA starting with START. */
-static void
-setup_preferred_alternate_classes_for_new_pseudos (int start)
-{
- int i, old_regno;
- int max_regno = max_reg_num ();
-
- for (i = start; i < max_regno; i++)
- {
- old_regno = ORIGINAL_REGNO (regno_reg_rtx[i]);
- ira_assert (i != old_regno);
- setup_reg_classes (i, reg_preferred_class (old_regno),
- reg_alternate_class (old_regno),
- reg_allocno_class (old_regno));
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " New r%d: setting preferred %s, alternative %s\n",
- i, reg_class_names[reg_preferred_class (old_regno)],
- reg_class_names[reg_alternate_class (old_regno)]);
- }
-}
-
-
-/* The number of entries allocated in reg_info. */
-static int allocated_reg_info_size;
-
-/* Regional allocation can create new pseudo-registers. This function
- expands some arrays for pseudo-registers. */
-static void
-expand_reg_info (void)
-{
- int i;
- int size = max_reg_num ();
-
- resize_reg_info ();
- for (i = allocated_reg_info_size; i < size; i++)
- setup_reg_classes (i, GENERAL_REGS, ALL_REGS, GENERAL_REGS);
- setup_preferred_alternate_classes_for_new_pseudos (allocated_reg_info_size);
- allocated_reg_info_size = size;
-}
-
-/* Return TRUE if there is too high register pressure in the function.
- It is used to decide when stack slot sharing is worth to do. */
-static bool
-too_high_register_pressure_p (void)
-{
- int i;
- enum reg_class pclass;
-
- for (i = 0; i < ira_pressure_classes_num; i++)
- {
- pclass = ira_pressure_classes[i];
- if (ira_loop_tree_root->reg_pressure[pclass] > 10000)
- return true;
- }
- return false;
-}
-
-
-
-/* Indicate that hard register number FROM was eliminated and replaced with
- an offset from hard register number TO. The status of hard registers live
- at the start of a basic block is updated by replacing a use of FROM with
- a use of TO. */
-
-void
-mark_elimination (int from, int to)
-{
- basic_block bb;
- bitmap r;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- r = DF_LR_IN (bb);
- if (bitmap_bit_p (r, from))
- {
- bitmap_clear_bit (r, from);
- bitmap_set_bit (r, to);
- }
- if (! df_live)
- continue;
- r = DF_LIVE_IN (bb);
- if (bitmap_bit_p (r, from))
- {
- bitmap_clear_bit (r, from);
- bitmap_set_bit (r, to);
- }
- }
-}
-
-
-
-/* The length of the following array. */
-int ira_reg_equiv_len;
-
-/* Info about equiv. info for each register. */
-struct ira_reg_equiv_s *ira_reg_equiv;
-
-/* Expand ira_reg_equiv if necessary. */
-void
-ira_expand_reg_equiv (void)
-{
- int old = ira_reg_equiv_len;
-
- if (ira_reg_equiv_len > max_reg_num ())
- return;
- ira_reg_equiv_len = max_reg_num () * 3 / 2 + 1;
- ira_reg_equiv
- = (struct ira_reg_equiv_s *) xrealloc (ira_reg_equiv,
- ira_reg_equiv_len
- * sizeof (struct ira_reg_equiv_s));
- gcc_assert (old < ira_reg_equiv_len);
- memset (ira_reg_equiv + old, 0,
- sizeof (struct ira_reg_equiv_s) * (ira_reg_equiv_len - old));
-}
-
-static void
-init_reg_equiv (void)
-{
- ira_reg_equiv_len = 0;
- ira_reg_equiv = NULL;
- ira_expand_reg_equiv ();
-}
-
-static void
-finish_reg_equiv (void)
-{
- free (ira_reg_equiv);
-}
-
-
-
-struct equivalence
-{
- /* Set when a REG_EQUIV note is found or created. Use to
- keep track of what memory accesses might be created later,
- e.g. by reload. */
- rtx replacement;
- rtx *src_p;
-
- /* The list of each instruction which initializes this register.
-
- NULL indicates we know nothing about this register's equivalence
- properties.
-
- An INSN_LIST with a NULL insn indicates this pseudo is already
- known to not have a valid equivalence. */
- rtx_insn_list *init_insns;
-
- /* Loop depth is used to recognize equivalences which appear
- to be present within the same loop (or in an inner loop). */
- short loop_depth;
- /* Nonzero if this had a preexisting REG_EQUIV note. */
- unsigned char is_arg_equivalence : 1;
- /* Set when an attempt should be made to replace a register
- with the associated src_p entry. */
- unsigned char replace : 1;
- /* Set if this register has no known equivalence. */
- unsigned char no_equiv : 1;
- /* Set if this register is mentioned in a paradoxical subreg. */
- unsigned char pdx_subregs : 1;
-};
-
-/* reg_equiv[N] (where N is a pseudo reg number) is the equivalence
- structure for that register. */
-static struct equivalence *reg_equiv;
-
-/* Used for communication between the following two functions. */
-struct equiv_mem_data
-{
- /* A MEM that we wish to ensure remains unchanged. */
- rtx equiv_mem;
-
- /* Set true if EQUIV_MEM is modified. */
- bool equiv_mem_modified;
-};
-
-/* If EQUIV_MEM is modified by modifying DEST, indicate that it is modified.
- Called via note_stores. */
-static void
-validate_equiv_mem_from_store (rtx dest, const_rtx set ATTRIBUTE_UNUSED,
- void *data)
-{
- struct equiv_mem_data *info = (struct equiv_mem_data *) data;
-
- if ((REG_P (dest)
- && reg_overlap_mentioned_p (dest, info->equiv_mem))
- || (MEM_P (dest)
- && anti_dependence (info->equiv_mem, dest)))
- info->equiv_mem_modified = true;
-}
-
-enum valid_equiv { valid_none, valid_combine, valid_reload };
-
-/* Verify that no store between START and the death of REG invalidates
- MEMREF. MEMREF is invalidated by modifying a register used in MEMREF,
- by storing into an overlapping memory location, or with a non-const
- CALL_INSN.
-
- Return VALID_RELOAD if MEMREF remains valid for both reload and
- combine_and_move insns, VALID_COMBINE if only valid for
- combine_and_move_insns, and VALID_NONE otherwise. */
-static enum valid_equiv
-validate_equiv_mem (rtx_insn *start, rtx reg, rtx memref)
-{
- rtx_insn *insn;
- rtx note;
- struct equiv_mem_data info = { memref, false };
- enum valid_equiv ret = valid_reload;
-
- /* If the memory reference has side effects or is volatile, it isn't a
- valid equivalence. */
- if (side_effects_p (memref))
- return valid_none;
-
- for (insn = start; insn; insn = NEXT_INSN (insn))
- {
- if (!INSN_P (insn))
- continue;
-
- if (find_reg_note (insn, REG_DEAD, reg))
- return ret;
-
- if (CALL_P (insn))
- {
- /* We can combine a reg def from one insn into a reg use in
- another over a call if the memory is readonly or the call
- const/pure. However, we can't set reg_equiv notes up for
- reload over any call. The problem is the equivalent form
- may reference a pseudo which gets assigned a call
- clobbered hard reg. When we later replace REG with its
- equivalent form, the value in the call-clobbered reg has
- been changed and all hell breaks loose. */
- ret = valid_combine;
- if (!MEM_READONLY_P (memref)
- && !RTL_CONST_OR_PURE_CALL_P (insn))
- return valid_none;
- }
-
- note_stores (insn, validate_equiv_mem_from_store, &info);
- if (info.equiv_mem_modified)
- return valid_none;
-
- /* If a register mentioned in MEMREF is modified via an
- auto-increment, we lose the equivalence. Do the same if one
- dies; although we could extend the life, it doesn't seem worth
- the trouble. */
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if ((REG_NOTE_KIND (note) == REG_INC
- || REG_NOTE_KIND (note) == REG_DEAD)
- && REG_P (XEXP (note, 0))
- && reg_overlap_mentioned_p (XEXP (note, 0), memref))
- return valid_none;
- }
-
- return valid_none;
-}
-
-/* Returns zero if X is known to be invariant. */
-static int
-equiv_init_varies_p (rtx x)
-{
- RTX_CODE code = GET_CODE (x);
- int i;
- const char *fmt;
-
- switch (code)
- {
- case MEM:
- return !MEM_READONLY_P (x) || equiv_init_varies_p (XEXP (x, 0));
-
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- return 0;
-
- case REG:
- return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x, 0);
-
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 1;
-
- /* Fall through. */
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- if (equiv_init_varies_p (XEXP (x, i)))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (equiv_init_varies_p (XVECEXP (x, i, j)))
- return 1;
- }
-
- return 0;
-}
-
-/* Returns nonzero if X (used to initialize register REGNO) is movable.
- X is only movable if the registers it uses have equivalent initializations
- which appear to be within the same loop (or in an inner loop) and movable
- or if they are not candidates for local_alloc and don't vary. */
-static int
-equiv_init_movable_p (rtx x, int regno)
-{
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
-
- switch (code)
- {
- case SET:
- return equiv_init_movable_p (SET_SRC (x), regno);
-
- case CLOBBER:
- return 0;
-
- case PRE_INC:
- case PRE_DEC:
- case POST_INC:
- case POST_DEC:
- case PRE_MODIFY:
- case POST_MODIFY:
- return 0;
-
- case REG:
- return ((reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth
- && reg_equiv[REGNO (x)].replace)
- || (REG_BASIC_BLOCK (REGNO (x)) < NUM_FIXED_BLOCKS
- && ! rtx_varies_p (x, 0)));
-
- case UNSPEC_VOLATILE:
- return 0;
-
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 0;
-
- /* Fall through. */
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (! equiv_init_movable_p (XEXP (x, i), regno))
- return 0;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (! equiv_init_movable_p (XVECEXP (x, i, j), regno))
- return 0;
- break;
- }
-
- return 1;
-}
-
-static bool memref_referenced_p (rtx memref, rtx x, bool read_p);
-
-/* Auxiliary function for memref_referenced_p. Process setting X for
- MEMREF store. */
-static bool
-process_set_for_memref_referenced_p (rtx memref, rtx x)
-{
- /* If we are setting a MEM, it doesn't count (its address does), but any
- other SET_DEST that has a MEM in it is referencing the MEM. */
- if (MEM_P (x))
- {
- if (memref_referenced_p (memref, XEXP (x, 0), true))
- return true;
- }
- else if (memref_referenced_p (memref, x, false))
- return true;
-
- return false;
-}
-
-/* TRUE if X references a memory location (as a read if READ_P) that
- would be affected by a store to MEMREF. */
-static bool
-memref_referenced_p (rtx memref, rtx x, bool read_p)
-{
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
-
- switch (code)
- {
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- CASE_CONST_ANY:
- case PC:
- case HIGH:
- case LO_SUM:
- return false;
-
- case REG:
- return (reg_equiv[REGNO (x)].replacement
- && memref_referenced_p (memref,
- reg_equiv[REGNO (x)].replacement, read_p));
-
- case MEM:
- /* Memory X might have another effective type than MEMREF. */
- if (read_p || true_dependence (memref, VOIDmode, x))
- return true;
- break;
-
- case SET:
- if (process_set_for_memref_referenced_p (memref, SET_DEST (x)))
- return true;
-
- return memref_referenced_p (memref, SET_SRC (x), true);
-
- case CLOBBER:
- if (process_set_for_memref_referenced_p (memref, XEXP (x, 0)))
- return true;
-
- return false;
-
- case PRE_DEC:
- case POST_DEC:
- case PRE_INC:
- case POST_INC:
- if (process_set_for_memref_referenced_p (memref, XEXP (x, 0)))
- return true;
-
- return memref_referenced_p (memref, XEXP (x, 0), true);
-
- case POST_MODIFY:
- case PRE_MODIFY:
- /* op0 = op0 + op1 */
- if (process_set_for_memref_referenced_p (memref, XEXP (x, 0)))
- return true;
-
- if (memref_referenced_p (memref, XEXP (x, 0), true))
- return true;
-
- return memref_referenced_p (memref, XEXP (x, 1), true);
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (memref_referenced_p (memref, XEXP (x, i), read_p))
- return true;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (memref_referenced_p (memref, XVECEXP (x, i, j), read_p))
- return true;
- break;
- }
-
- return false;
-}
-
-/* TRUE if some insn in the range (START, END] references a memory location
- that would be affected by a store to MEMREF.
-
- Callers should not call this routine if START is after END in the
- RTL chain. */
-
-static int
-memref_used_between_p (rtx memref, rtx_insn *start, rtx_insn *end)
-{
- rtx_insn *insn;
-
- for (insn = NEXT_INSN (start);
- insn && insn != NEXT_INSN (end);
- insn = NEXT_INSN (insn))
- {
- if (!NONDEBUG_INSN_P (insn))
- continue;
-
- if (memref_referenced_p (memref, PATTERN (insn), false))
- return 1;
-
- /* Nonconst functions may access memory. */
- if (CALL_P (insn) && (! RTL_CONST_CALL_P (insn)))
- return 1;
- }
-
- gcc_assert (insn == NEXT_INSN (end));
- return 0;
-}
-
-/* Mark REG as having no known equivalence.
- Some instructions might have been processed before and furnished
- with REG_EQUIV notes for this register; these notes will have to be
- removed.
- STORE is the piece of RTL that does the non-constant / conflicting
- assignment - a SET, CLOBBER or REG_INC note. It is currently not used,
- but needs to be there because this function is called from note_stores. */
-static void
-no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- int regno;
- rtx_insn_list *list;
-
- if (!REG_P (reg))
- return;
- regno = REGNO (reg);
- reg_equiv[regno].no_equiv = 1;
- list = reg_equiv[regno].init_insns;
- if (list && list->insn () == NULL)
- return;
- reg_equiv[regno].init_insns = gen_rtx_INSN_LIST (VOIDmode, NULL_RTX, NULL);
- reg_equiv[regno].replacement = NULL_RTX;
- /* This doesn't matter for equivalences made for argument registers, we
- should keep their initialization insns. */
- if (reg_equiv[regno].is_arg_equivalence)
- return;
- ira_reg_equiv[regno].defined_p = false;
- ira_reg_equiv[regno].init_insns = NULL;
- for (; list; list = list->next ())
- {
- rtx_insn *insn = list->insn ();
- remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
- }
-}
-
-/* Check whether the SUBREG is a paradoxical subreg and set the result
- in PDX_SUBREGS. */
-
-static void
-set_paradoxical_subreg (rtx_insn *insn)
-{
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
- {
- const_rtx subreg = *iter;
- if (GET_CODE (subreg) == SUBREG)
- {
- const_rtx reg = SUBREG_REG (subreg);
- if (REG_P (reg) && paradoxical_subreg_p (subreg))
- reg_equiv[REGNO (reg)].pdx_subregs = true;
- }
- }
-}
-
-/* In DEBUG_INSN location adjust REGs from CLEARED_REGS bitmap to the
- equivalent replacement. */
-
-static rtx
-adjust_cleared_regs (rtx loc, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
-{
- if (REG_P (loc))
- {
- bitmap cleared_regs = (bitmap) data;
- if (bitmap_bit_p (cleared_regs, REGNO (loc)))
- return simplify_replace_fn_rtx (copy_rtx (*reg_equiv[REGNO (loc)].src_p),
- NULL_RTX, adjust_cleared_regs, data);
- }
- return NULL_RTX;
-}
-
-/* Given register REGNO is set only once, return true if the defining
- insn dominates all uses. */
-
-static bool
-def_dominates_uses (int regno)
-{
- df_ref def = DF_REG_DEF_CHAIN (regno);
-
- struct df_insn_info *def_info = DF_REF_INSN_INFO (def);
- /* If this is an artificial def (eh handler regs, hard frame pointer
- for non-local goto, regs defined on function entry) then def_info
- is NULL and the reg is always live before any use. We might
- reasonably return true in that case, but since the only call
- of this function is currently here in ira.c when we are looking
- at a defining insn we can't have an artificial def as that would
- bump DF_REG_DEF_COUNT. */
- gcc_assert (DF_REG_DEF_COUNT (regno) == 1 && def_info != NULL);
-
- rtx_insn *def_insn = DF_REF_INSN (def);
- basic_block def_bb = BLOCK_FOR_INSN (def_insn);
-
- for (df_ref use = DF_REG_USE_CHAIN (regno);
- use;
- use = DF_REF_NEXT_REG (use))
- {
- struct df_insn_info *use_info = DF_REF_INSN_INFO (use);
- /* Only check real uses, not artificial ones. */
- if (use_info)
- {
- rtx_insn *use_insn = DF_REF_INSN (use);
- if (!DEBUG_INSN_P (use_insn))
- {
- basic_block use_bb = BLOCK_FOR_INSN (use_insn);
- if (use_bb != def_bb
- ? !dominated_by_p (CDI_DOMINATORS, use_bb, def_bb)
- : DF_INSN_INFO_LUID (use_info) < DF_INSN_INFO_LUID (def_info))
- return false;
- }
- }
- }
- return true;
-}
-
-/* Scan the instructions before update_equiv_regs. Record which registers
- are referenced as paradoxical subregs. Also check for cases in which
- the current function needs to save a register that one of its call
- instructions clobbers.
-
- These things are logically unrelated, but it's more efficient to do
- them together. */
-
-static void
-update_equiv_regs_prescan (void)
-{
- basic_block bb;
- rtx_insn *insn;
- function_abi_aggregator callee_abis;
-
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- {
- set_paradoxical_subreg (insn);
- if (CALL_P (insn))
- callee_abis.note_callee_abi (insn_callee_abi (insn));
- }
-
- HARD_REG_SET extra_caller_saves = callee_abis.caller_save_regs (*crtl->abi);
- if (!hard_reg_set_empty_p (extra_caller_saves))
- for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
- if (TEST_HARD_REG_BIT (extra_caller_saves, regno))
- df_set_regs_ever_live (regno, true);
-}
-
-/* Find registers that are equivalent to a single value throughout the
- compilation (either because they can be referenced in memory or are
- set once from a single constant). Lower their priority for a
- register.
-
- If such a register is only referenced once, try substituting its
- value into the using insn. If it succeeds, we can eliminate the
- register completely.
-
- Initialize init_insns in ira_reg_equiv array. */
-static void
-update_equiv_regs (void)
-{
- rtx_insn *insn;
- basic_block bb;
-
- /* Scan the insns and find which registers have equivalences. Do this
- in a separate scan of the insns because (due to -fcse-follow-jumps)
- a register can be set below its use. */
- bitmap setjmp_crosses = regstat_get_setjmp_crosses ();
- FOR_EACH_BB_FN (bb, cfun)
- {
- int loop_depth = bb_loop_depth (bb);
-
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- rtx note;
- rtx set;
- rtx dest, src;
- int regno;
-
- if (! INSN_P (insn))
- continue;
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_INC)
- no_equiv (XEXP (note, 0), note, NULL);
-
- set = single_set (insn);
-
- /* If this insn contains more (or less) than a single SET,
- only mark all destinations as having no known equivalence. */
- if (set == NULL_RTX
- || side_effects_p (SET_SRC (set)))
- {
- note_pattern_stores (PATTERN (insn), no_equiv, NULL);
- continue;
- }
- else if (GET_CODE (PATTERN (insn)) == PARALLEL)
- {
- int i;
-
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- {
- rtx part = XVECEXP (PATTERN (insn), 0, i);
- if (part != set)
- note_pattern_stores (part, no_equiv, NULL);
- }
- }
-
- dest = SET_DEST (set);
- src = SET_SRC (set);
-
- /* See if this is setting up the equivalence between an argument
- register and its stack slot. */
- note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note)
- {
- gcc_assert (REG_P (dest));
- regno = REGNO (dest);
-
- /* Note that we don't want to clear init_insns in
- ira_reg_equiv even if there are multiple sets of this
- register. */
- reg_equiv[regno].is_arg_equivalence = 1;
-
- /* The insn result can have equivalence memory although
- the equivalence is not set up by the insn. We add
- this insn to init insns as it is a flag for now that
- regno has an equivalence. We will remove the insn
- from init insn list later. */
- if (rtx_equal_p (src, XEXP (note, 0)) || MEM_P (XEXP (note, 0)))
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[regno].init_insns);
-
- /* Continue normally in case this is a candidate for
- replacements. */
- }
-
- if (!optimize)
- continue;
-
- /* We only handle the case of a pseudo register being set
- once, or always to the same value. */
- /* ??? The mn10200 port breaks if we add equivalences for
- values that need an ADDRESS_REGS register and set them equivalent
- to a MEM of a pseudo. The actual problem is in the over-conservative
- handling of INPADDR_ADDRESS / INPUT_ADDRESS / INPUT triples in
- calculate_needs, but we traditionally work around this problem
- here by rejecting equivalences when the destination is in a register
- that's likely spilled. This is fragile, of course, since the
- preferred class of a pseudo depends on all instructions that set
- or use it. */
-
- if (!REG_P (dest)
- || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
- || (reg_equiv[regno].init_insns
- && reg_equiv[regno].init_insns->insn () == NULL)
- || (targetm.class_likely_spilled_p (reg_preferred_class (regno))
- && MEM_P (src) && ! reg_equiv[regno].is_arg_equivalence))
- {
- /* This might be setting a SUBREG of a pseudo, a pseudo that is
- also set somewhere else to a constant. */
- note_pattern_stores (set, no_equiv, NULL);
- continue;
- }
-
- /* Don't set reg mentioned in a paradoxical subreg
- equivalent to a mem. */
- if (MEM_P (src) && reg_equiv[regno].pdx_subregs)
- {
- note_pattern_stores (set, no_equiv, NULL);
- continue;
- }
-
- note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
- /* cse sometimes generates function invariants, but doesn't put a
- REG_EQUAL note on the insn. Since this note would be redundant,
- there's no point creating it earlier than here. */
- if (! note && ! rtx_varies_p (src, 0))
- note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
-
- /* Don't bother considering a REG_EQUAL note containing an EXPR_LIST
- since it represents a function call. */
- if (note && GET_CODE (XEXP (note, 0)) == EXPR_LIST)
- note = NULL_RTX;
-
- if (DF_REG_DEF_COUNT (regno) != 1)
- {
- bool equal_p = true;
- rtx_insn_list *list;
-
- /* If we have already processed this pseudo and determined it
- cannot have an equivalence, then honor that decision. */
- if (reg_equiv[regno].no_equiv)
- continue;
-
- if (! note
- || rtx_varies_p (XEXP (note, 0), 0)
- || (reg_equiv[regno].replacement
- && ! rtx_equal_p (XEXP (note, 0),
- reg_equiv[regno].replacement)))
- {
- no_equiv (dest, set, NULL);
- continue;
- }
-
- list = reg_equiv[regno].init_insns;
- for (; list; list = list->next ())
- {
- rtx note_tmp;
- rtx_insn *insn_tmp;
-
- insn_tmp = list->insn ();
- note_tmp = find_reg_note (insn_tmp, REG_EQUAL, NULL_RTX);
- gcc_assert (note_tmp);
- if (! rtx_equal_p (XEXP (note, 0), XEXP (note_tmp, 0)))
- {
- equal_p = false;
- break;
- }
- }
-
- if (! equal_p)
- {
- no_equiv (dest, set, NULL);
- continue;
- }
- }
-
- /* Record this insn as initializing this register. */
- reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv[regno].init_insns);
-
- /* If this register is known to be equal to a constant, record that
- it is always equivalent to the constant.
- Note that it is possible to have a register use before
- the def in loops (see gcc.c-torture/execute/pr79286.c)
- where the reg is undefined on first use. If the def insn
- won't trap we can use it as an equivalence, effectively
- choosing the "undefined" value for the reg to be the
- same as the value set by the def. */
- if (DF_REG_DEF_COUNT (regno) == 1
- && note
- && !rtx_varies_p (XEXP (note, 0), 0)
- && (!may_trap_or_fault_p (XEXP (note, 0))
- || def_dominates_uses (regno)))
- {
- rtx note_value = XEXP (note, 0);
- remove_note (insn, note);
- set_unique_reg_note (insn, REG_EQUIV, note_value);
- }
-
- /* If this insn introduces a "constant" register, decrease the priority
- of that register. Record this insn if the register is only used once
- more and the equivalence value is the same as our source.
-
- The latter condition is checked for two reasons: First, it is an
- indication that it may be more efficient to actually emit the insn
- as written (if no registers are available, reload will substitute
- the equivalence). Secondly, it avoids problems with any registers
- dying in this insn whose death notes would be missed.
-
- If we don't have a REG_EQUIV note, see if this insn is loading
- a register used only in one basic block from a MEM. If so, and the
- MEM remains unchanged for the life of the register, add a REG_EQUIV
- note. */
- note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
-
- rtx replacement = NULL_RTX;
- if (note)
- replacement = XEXP (note, 0);
- else if (REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
- && MEM_P (SET_SRC (set)))
- {
- enum valid_equiv validity;
- validity = validate_equiv_mem (insn, dest, SET_SRC (set));
- if (validity != valid_none)
- {
- replacement = copy_rtx (SET_SRC (set));
- if (validity == valid_reload)
- note = set_unique_reg_note (insn, REG_EQUIV, replacement);
- }
- }
-
- /* If we haven't done so, record for reload that this is an
- equivalencing insn. */
- if (note && !reg_equiv[regno].is_arg_equivalence)
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[regno].init_insns);
-
- if (replacement)
- {
- reg_equiv[regno].replacement = replacement;
- reg_equiv[regno].src_p = &SET_SRC (set);
- reg_equiv[regno].loop_depth = (short) loop_depth;
-
- /* Don't mess with things live during setjmp. */
- if (optimize && !bitmap_bit_p (setjmp_crosses, regno))
- {
- /* If the register is referenced exactly twice, meaning it is
- set once and used once, indicate that the reference may be
- replaced by the equivalence we computed above. Do this
- even if the register is only used in one block so that
- dependencies can be handled where the last register is
- used in a different block (i.e. HIGH / LO_SUM sequences)
- and to reduce the number of registers alive across
- calls. */
-
- if (REG_N_REFS (regno) == 2
- && (rtx_equal_p (replacement, src)
- || ! equiv_init_varies_p (src))
- && NONJUMP_INSN_P (insn)
- && equiv_init_movable_p (PATTERN (insn), regno))
- reg_equiv[regno].replace = 1;
- }
- }
- }
- }
-}
-
-/* For insns that set a MEM to the contents of a REG that is only used
- in a single basic block, see if the register is always equivalent
- to that memory location and if moving the store from INSN to the
- insn that sets REG is safe. If so, put a REG_EQUIV note on the
- initializing insn. */
-static void
-add_store_equivs (void)
-{
- auto_bitmap seen_insns;
-
- for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- rtx set, src, dest;
- unsigned regno;
- rtx_insn *init_insn;
-
- bitmap_set_bit (seen_insns, INSN_UID (insn));
-
- if (! INSN_P (insn))
- continue;
-
- set = single_set (insn);
- if (! set)
- continue;
-
- dest = SET_DEST (set);
- src = SET_SRC (set);
-
- /* Don't add a REG_EQUIV note if the insn already has one. The existing
- REG_EQUIV is likely more useful than the one we are adding. */
- if (MEM_P (dest) && REG_P (src)
- && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
- && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
- && DF_REG_DEF_COUNT (regno) == 1
- && ! reg_equiv[regno].pdx_subregs
- && reg_equiv[regno].init_insns != NULL
- && (init_insn = reg_equiv[regno].init_insns->insn ()) != 0
- && bitmap_bit_p (seen_insns, INSN_UID (init_insn))
- && ! find_reg_note (init_insn, REG_EQUIV, NULL_RTX)
- && validate_equiv_mem (init_insn, src, dest) == valid_reload
- && ! memref_used_between_p (dest, init_insn, insn)
- /* Attaching a REG_EQUIV note will fail if INIT_INSN has
- multiple sets. */
- && set_unique_reg_note (init_insn, REG_EQUIV, copy_rtx (dest)))
- {
- /* This insn makes the equivalence, not the one initializing
- the register. */
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
- df_notes_rescan (init_insn);
- if (dump_file)
- fprintf (dump_file,
- "Adding REG_EQUIV to insn %d for source of insn %d\n",
- INSN_UID (init_insn),
- INSN_UID (insn));
- }
- }
-}
-
-/* Scan all regs killed in an insn to see if any of them are registers
- only used that once. If so, see if we can replace the reference
- with the equivalent form. If we can, delete the initializing
- reference and this register will go away. If we can't replace the
- reference, and the initializing reference is within the same loop
- (or in an inner loop), then move the register initialization just
- before the use, so that they are in the same basic block. */
-static void
-combine_and_move_insns (void)
-{
- auto_bitmap cleared_regs;
- int max = max_reg_num ();
-
- for (int regno = FIRST_PSEUDO_REGISTER; regno < max; regno++)
- {
- if (!reg_equiv[regno].replace)
- continue;
-
- rtx_insn *use_insn = 0;
- for (df_ref use = DF_REG_USE_CHAIN (regno);
- use;
- use = DF_REF_NEXT_REG (use))
- if (DF_REF_INSN_INFO (use))
- {
- if (DEBUG_INSN_P (DF_REF_INSN (use)))
- continue;
- gcc_assert (!use_insn);
- use_insn = DF_REF_INSN (use);
- }
- gcc_assert (use_insn);
-
- /* Don't substitute into jumps. indirect_jump_optimize does
- this for anything we are prepared to handle. */
- if (JUMP_P (use_insn))
- continue;
-
- /* Also don't substitute into a conditional trap insn -- it can become
- an unconditional trap, and that is a flow control insn. */
- if (GET_CODE (PATTERN (use_insn)) == TRAP_IF)
- continue;
-
- df_ref def = DF_REG_DEF_CHAIN (regno);
- gcc_assert (DF_REG_DEF_COUNT (regno) == 1 && DF_REF_INSN_INFO (def));
- rtx_insn *def_insn = DF_REF_INSN (def);
-
- /* We may not move instructions that can throw, since that
- changes basic block boundaries and we are not prepared to
- adjust the CFG to match. */
- if (can_throw_internal (def_insn))
- continue;
-
- /* Instructions with multiple sets can only be moved if DF analysis is
- performed for all of the registers set. See PR91052. */
- if (multiple_sets (def_insn))
- continue;
-
- basic_block use_bb = BLOCK_FOR_INSN (use_insn);
- basic_block def_bb = BLOCK_FOR_INSN (def_insn);
- if (bb_loop_depth (use_bb) > bb_loop_depth (def_bb))
- continue;
-
- if (asm_noperands (PATTERN (def_insn)) < 0
- && validate_replace_rtx (regno_reg_rtx[regno],
- *reg_equiv[regno].src_p, use_insn))
- {
- rtx link;
- /* Append the REG_DEAD notes from def_insn. */
- for (rtx *p = &REG_NOTES (def_insn); (link = *p) != 0; )
- {
- if (REG_NOTE_KIND (XEXP (link, 0)) == REG_DEAD)
- {
- *p = XEXP (link, 1);
- XEXP (link, 1) = REG_NOTES (use_insn);
- REG_NOTES (use_insn) = link;
- }
- else
- p = &XEXP (link, 1);
- }
-
- remove_death (regno, use_insn);
- SET_REG_N_REFS (regno, 0);
- REG_FREQ (regno) = 0;
- df_ref use;
- FOR_EACH_INSN_USE (use, def_insn)
- {
- unsigned int use_regno = DF_REF_REGNO (use);
- if (!HARD_REGISTER_NUM_P (use_regno))
- reg_equiv[use_regno].replace = 0;
- }
-
- delete_insn (def_insn);
-
- reg_equiv[regno].init_insns = NULL;
- ira_reg_equiv[regno].init_insns = NULL;
- bitmap_set_bit (cleared_regs, regno);
- }
-
- /* Move the initialization of the register to just before
- USE_INSN. Update the flow information. */
- else if (prev_nondebug_insn (use_insn) != def_insn)
- {
- rtx_insn *new_insn;
-
- new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
- REG_NOTES (new_insn) = REG_NOTES (def_insn);
- REG_NOTES (def_insn) = 0;
- /* Rescan it to process the notes. */
- df_insn_rescan (new_insn);
-
- /* Make sure this insn is recognized before reload begins,
- otherwise eliminate_regs_in_insn will die. */
- INSN_CODE (new_insn) = INSN_CODE (def_insn);
-
- delete_insn (def_insn);
-
- XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
-
- REG_BASIC_BLOCK (regno) = use_bb->index;
- REG_N_CALLS_CROSSED (regno) = 0;
-
- if (use_insn == BB_HEAD (use_bb))
- BB_HEAD (use_bb) = new_insn;
-
- /* We know regno dies in use_insn, but inside a loop
- REG_DEAD notes might be missing when def_insn was in
- another basic block. However, when we move def_insn into
- this bb we'll definitely get a REG_DEAD note and reload
- will see the death. It's possible that update_equiv_regs
- set up an equivalence referencing regno for a reg set by
- use_insn, when regno was seen as non-local. Now that
- regno is local to this block, and dies, such an
- equivalence is invalid. */
- if (find_reg_note (use_insn, REG_EQUIV, regno_reg_rtx[regno]))
- {
- rtx set = single_set (use_insn);
- if (set && REG_P (SET_DEST (set)))
- no_equiv (SET_DEST (set), set, NULL);
- }
-
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
- bitmap_set_bit (cleared_regs, regno);
- }
- }
-
- if (!bitmap_empty_p (cleared_regs))
- {
- basic_block bb;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs);
- bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs);
- if (!df_live)
- continue;
- bitmap_and_compl_into (DF_LIVE_IN (bb), cleared_regs);
- bitmap_and_compl_into (DF_LIVE_OUT (bb), cleared_regs);
- }
-
- /* Last pass - adjust debug insns referencing cleared regs. */
- if (MAY_HAVE_DEBUG_BIND_INSNS)
- for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (DEBUG_BIND_INSN_P (insn))
- {
- rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
- INSN_VAR_LOCATION_LOC (insn)
- = simplify_replace_fn_rtx (old_loc, NULL_RTX,
- adjust_cleared_regs,
- (void *) cleared_regs);
- if (old_loc != INSN_VAR_LOCATION_LOC (insn))
- df_insn_rescan (insn);
- }
- }
-}
-
-/* A pass over indirect jumps, converting simple cases to direct jumps.
- Combine does this optimization too, but only within a basic block. */
-static void
-indirect_jump_optimize (void)
-{
- basic_block bb;
- bool rebuild_p = false;
-
- FOR_EACH_BB_REVERSE_FN (bb, cfun)
- {
- rtx_insn *insn = BB_END (bb);
- if (!JUMP_P (insn)
- || find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
- continue;
-
- rtx x = pc_set (insn);
- if (!x || !REG_P (SET_SRC (x)))
- continue;
-
- int regno = REGNO (SET_SRC (x));
- if (DF_REG_DEF_COUNT (regno) == 1)
- {
- df_ref def = DF_REG_DEF_CHAIN (regno);
- if (!DF_REF_IS_ARTIFICIAL (def))
- {
- rtx_insn *def_insn = DF_REF_INSN (def);
- rtx lab = NULL_RTX;
- rtx set = single_set (def_insn);
- if (set && GET_CODE (SET_SRC (set)) == LABEL_REF)
- lab = SET_SRC (set);
- else
- {
- rtx eqnote = find_reg_note (def_insn, REG_EQUAL, NULL_RTX);
- if (eqnote && GET_CODE (XEXP (eqnote, 0)) == LABEL_REF)
- lab = XEXP (eqnote, 0);
- }
- if (lab && validate_replace_rtx (SET_SRC (x), lab, insn))
- rebuild_p = true;
- }
- }
- }
-
- if (rebuild_p)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- if (purge_all_dead_edges ())
- delete_unreachable_blocks ();
- timevar_pop (TV_JUMP);
- }
-}
-
-/* Set up fields memory, constant, and invariant from init_insns in
- the structures of array ira_reg_equiv. */
-static void
-setup_reg_equiv (void)
-{
- int i;
- rtx_insn_list *elem, *prev_elem, *next_elem;
- rtx_insn *insn;
- rtx set, x;
-
- for (i = FIRST_PSEUDO_REGISTER; i < ira_reg_equiv_len; i++)
- for (prev_elem = NULL, elem = ira_reg_equiv[i].init_insns;
- elem;
- prev_elem = elem, elem = next_elem)
- {
- next_elem = elem->next ();
- insn = elem->insn ();
- set = single_set (insn);
-
- /* Init insns can set up equivalence when the reg is a destination or
- a source (in this case the destination is memory). */
- if (set != 0 && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))))
- {
- if ((x = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL)
- {
- x = XEXP (x, 0);
- if (REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == (unsigned int) i
- && ! rtx_equal_p (SET_SRC (set), x) && MEM_P (x))
- {
- /* This insn reporting the equivalence but
- actually not setting it. Remove it from the
- list. */
- if (prev_elem == NULL)
- ira_reg_equiv[i].init_insns = next_elem;
- else
- XEXP (prev_elem, 1) = next_elem;
- elem = prev_elem;
- }
- }
- else if (REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == (unsigned int) i)
- x = SET_SRC (set);
- else
- {
- gcc_assert (REG_P (SET_SRC (set))
- && REGNO (SET_SRC (set)) == (unsigned int) i);
- x = SET_DEST (set);
- }
- if (! function_invariant_p (x)
- || ! flag_pic
- /* A function invariant is often CONSTANT_P but may
- include a register. We promise to only pass
- CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
- || (CONSTANT_P (x) && LEGITIMATE_PIC_OPERAND_P (x)))
- {
- /* It can happen that a REG_EQUIV note contains a MEM
- that is not a legitimate memory operand. As later
- stages of reload assume that all addresses found in
- the lra_regno_equiv_* arrays were originally
- legitimate, we ignore such REG_EQUIV notes. */
- if (memory_operand (x, VOIDmode))
- {
- ira_reg_equiv[i].defined_p = true;
- ira_reg_equiv[i].memory = x;
- continue;
- }
- else if (function_invariant_p (x))
- {
- machine_mode mode;
-
- mode = GET_MODE (SET_DEST (set));
- if (GET_CODE (x) == PLUS
- || x == frame_pointer_rtx || x == arg_pointer_rtx)
- /* This is PLUS of frame pointer and a constant,
- or fp, or argp. */
- ira_reg_equiv[i].invariant = x;
- else if (targetm.legitimate_constant_p (mode, x))
- ira_reg_equiv[i].constant = x;
- else
- {
- ira_reg_equiv[i].memory = force_const_mem (mode, x);
- if (ira_reg_equiv[i].memory == NULL_RTX)
- {
- ira_reg_equiv[i].defined_p = false;
- ira_reg_equiv[i].init_insns = NULL;
- break;
- }
- }
- ira_reg_equiv[i].defined_p = true;
- continue;
- }
- }
- }
- ira_reg_equiv[i].defined_p = false;
- ira_reg_equiv[i].init_insns = NULL;
- break;
- }
-}
-
-
-
-/* Print chain C to FILE. */
-static void
-print_insn_chain (FILE *file, class insn_chain *c)
-{
- fprintf (file, "insn=%d, ", INSN_UID (c->insn));
- bitmap_print (file, &c->live_throughout, "live_throughout: ", ", ");
- bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
-}
-
-
-/* Print all reload_insn_chains to FILE. */
-static void
-print_insn_chains (FILE *file)
-{
- class insn_chain *c;
- for (c = reload_insn_chain; c ; c = c->next)
- print_insn_chain (file, c);
-}
-
-/* Return true if pseudo REGNO should be added to set live_throughout
- or dead_or_set of the insn chains for reload consideration. */
-static bool
-pseudo_for_reload_consideration_p (int regno)
-{
- /* Consider spilled pseudos too for IRA because they still have a
- chance to get hard-registers in the reload when IRA is used. */
- return (reg_renumber[regno] >= 0 || ira_conflicts_p);
-}
-
-/* Return true if we can track the individual bytes of subreg X.
- When returning true, set *OUTER_SIZE to the number of bytes in
- X itself, *INNER_SIZE to the number of bytes in the inner register
- and *START to the offset of the first byte. */
-static bool
-get_subreg_tracking_sizes (rtx x, HOST_WIDE_INT *outer_size,
- HOST_WIDE_INT *inner_size, HOST_WIDE_INT *start)
-{
- rtx reg = regno_reg_rtx[REGNO (SUBREG_REG (x))];
- return (GET_MODE_SIZE (GET_MODE (x)).is_constant (outer_size)
- && GET_MODE_SIZE (GET_MODE (reg)).is_constant (inner_size)
- && SUBREG_BYTE (x).is_constant (start));
-}
-
-/* Init LIVE_SUBREGS[ALLOCNUM] and LIVE_SUBREGS_USED[ALLOCNUM] for
- a register with SIZE bytes, making the register live if INIT_VALUE. */
-static void
-init_live_subregs (bool init_value, sbitmap *live_subregs,
- bitmap live_subregs_used, int allocnum, int size)
-{
- gcc_assert (size > 0);
-
- /* Been there, done that. */
- if (bitmap_bit_p (live_subregs_used, allocnum))
- return;
-
- /* Create a new one. */
- if (live_subregs[allocnum] == NULL)
- live_subregs[allocnum] = sbitmap_alloc (size);
-
- /* If the entire reg was live before blasting into subregs, we need
- to init all of the subregs to ones else init to 0. */
- if (init_value)
- bitmap_ones (live_subregs[allocnum]);
- else
- bitmap_clear (live_subregs[allocnum]);
-
- bitmap_set_bit (live_subregs_used, allocnum);
-}
-
-/* Walk the insns of the current function and build reload_insn_chain,
- and record register life information. */
-static void
-build_insn_chain (void)
-{
- unsigned int i;
- class insn_chain **p = &reload_insn_chain;
- basic_block bb;
- class insn_chain *c = NULL;
- class insn_chain *next = NULL;
- auto_bitmap live_relevant_regs;
- auto_bitmap elim_regset;
- /* live_subregs is a vector used to keep accurate information about
- which hardregs are live in multiword pseudos. live_subregs and
- live_subregs_used are indexed by pseudo number. The live_subreg
- entry for a particular pseudo is only used if the corresponding
- element is non zero in live_subregs_used. The sbitmap size of
- live_subreg[allocno] is number of bytes that the pseudo can
- occupy. */
- sbitmap *live_subregs = XCNEWVEC (sbitmap, max_regno);
- auto_bitmap live_subregs_used;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (eliminable_regset, i))
- bitmap_set_bit (elim_regset, i);
- FOR_EACH_BB_REVERSE_FN (bb, cfun)
- {
- bitmap_iterator bi;
- rtx_insn *insn;
-
- CLEAR_REG_SET (live_relevant_regs);
- bitmap_clear (live_subregs_used);
-
- EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), 0, i, bi)
- {
- if (i >= FIRST_PSEUDO_REGISTER)
- break;
- bitmap_set_bit (live_relevant_regs, i);
- }
-
- EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb),
- FIRST_PSEUDO_REGISTER, i, bi)
- {
- if (pseudo_for_reload_consideration_p (i))
- bitmap_set_bit (live_relevant_regs, i);
- }
-
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- if (!NOTE_P (insn) && !BARRIER_P (insn))
- {
- struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- df_ref def, use;
-
- c = new_insn_chain ();
- c->next = next;
- next = c;
- *p = c;
- p = &c->prev;
-
- c->insn = insn;
- c->block = bb->index;
-
- if (NONDEBUG_INSN_P (insn))
- FOR_EACH_INSN_INFO_DEF (def, insn_info)
- {
- unsigned int regno = DF_REF_REGNO (def);
-
- /* Ignore may clobbers because these are generated
- from calls. However, every other kind of def is
- added to dead_or_set. */
- if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- if (!fixed_regs[regno])
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- else if (pseudo_for_reload_consideration_p (regno))
- bitmap_set_bit (&c->dead_or_set, regno);
- }
-
- if ((regno < FIRST_PSEUDO_REGISTER
- || reg_renumber[regno] >= 0
- || ira_conflicts_p)
- && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
- {
- rtx reg = DF_REF_REG (def);
- HOST_WIDE_INT outer_size, inner_size, start;
-
- /* We can usually track the liveness of individual
- bytes within a subreg. The only exceptions are
- subregs wrapped in ZERO_EXTRACTs and subregs whose
- size is not known; in those cases we need to be
- conservative and treat the definition as a partial
- definition of the full register rather than a full
- definition of a specific part of the register. */
- if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT)
- && get_subreg_tracking_sizes (reg, &outer_size,
- &inner_size, &start))
- {
- HOST_WIDE_INT last = start + outer_size;
-
- init_live_subregs
- (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used, regno,
- inner_size);
-
- if (!DF_REF_FLAGS_IS_SET
- (def, DF_REF_STRICT_LOW_PART))
- {
- /* Expand the range to cover entire words.
- Bytes added here are "don't care". */
- start
- = start / UNITS_PER_WORD * UNITS_PER_WORD;
- last = ((last + UNITS_PER_WORD - 1)
- / UNITS_PER_WORD * UNITS_PER_WORD);
- }
-
- /* Ignore the paradoxical bits. */
- if (last > SBITMAP_SIZE (live_subregs[regno]))
- last = SBITMAP_SIZE (live_subregs[regno]);
-
- while (start < last)
- {
- bitmap_clear_bit (live_subregs[regno], start);
- start++;
- }
-
- if (bitmap_empty_p (live_subregs[regno]))
- {
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_clear_bit (live_relevant_regs, regno);
- }
- else
- /* Set live_relevant_regs here because
- that bit has to be true to get us to
- look at the live_subregs fields. */
- bitmap_set_bit (live_relevant_regs, regno);
- }
- else
- {
- /* DF_REF_PARTIAL is generated for
- subregs, STRICT_LOW_PART, and
- ZERO_EXTRACT. We handle the subreg
- case above so here we have to keep from
- modeling the def as a killing def. */
- if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL))
- {
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_clear_bit (live_relevant_regs, regno);
- }
- }
- }
- }
-
- bitmap_and_compl_into (live_relevant_regs, elim_regset);
- bitmap_copy (&c->live_throughout, live_relevant_regs);
-
- if (NONDEBUG_INSN_P (insn))
- FOR_EACH_INSN_INFO_USE (use, insn_info)
- {
- unsigned int regno = DF_REF_REGNO (use);
- rtx reg = DF_REF_REG (use);
-
- /* DF_REF_READ_WRITE on a use means that this use
- is fabricated from a def that is a partial set
- to a multiword reg. Here, we only model the
- subreg case that is not wrapped in ZERO_EXTRACT
- precisely so we do not need to look at the
- fabricated use. */
- if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE)
- && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)
- && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
- continue;
-
- /* Add the last use of each var to dead_or_set. */
- if (!bitmap_bit_p (live_relevant_regs, regno))
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- if (!fixed_regs[regno])
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- else if (pseudo_for_reload_consideration_p (regno))
- bitmap_set_bit (&c->dead_or_set, regno);
- }
-
- if (regno < FIRST_PSEUDO_REGISTER
- || pseudo_for_reload_consideration_p (regno))
- {
- HOST_WIDE_INT outer_size, inner_size, start;
- if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (use,
- DF_REF_SIGN_EXTRACT
- | DF_REF_ZERO_EXTRACT)
- && get_subreg_tracking_sizes (reg, &outer_size,
- &inner_size, &start))
- {
- HOST_WIDE_INT last = start + outer_size;
-
- init_live_subregs
- (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used, regno,
- inner_size);
-
- /* Ignore the paradoxical bits. */
- if (last > SBITMAP_SIZE (live_subregs[regno]))
- last = SBITMAP_SIZE (live_subregs[regno]);
-
- while (start < last)
- {
- bitmap_set_bit (live_subregs[regno], start);
- start++;
- }
- }
- else
- /* Resetting the live_subregs_used is
- effectively saying do not use the subregs
- because we are reading the whole
- pseudo. */
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_set_bit (live_relevant_regs, regno);
- }
- }
- }
- }
-
- /* FIXME!! The following code is a disaster. Reload needs to see the
- labels and jump tables that are just hanging out in between
- the basic blocks. See pr33676. */
- insn = BB_HEAD (bb);
-
- /* Skip over the barriers and cruft. */
- while (insn && (BARRIER_P (insn) || NOTE_P (insn)
- || BLOCK_FOR_INSN (insn) == bb))
- insn = PREV_INSN (insn);
-
- /* While we add anything except barriers and notes, the focus is
- to get the labels and jump tables into the
- reload_insn_chain. */
- while (insn)
- {
- if (!NOTE_P (insn) && !BARRIER_P (insn))
- {
- if (BLOCK_FOR_INSN (insn))
- break;
-
- c = new_insn_chain ();
- c->next = next;
- next = c;
- *p = c;
- p = &c->prev;
-
- /* The block makes no sense here, but it is what the old
- code did. */
- c->block = bb->index;
- c->insn = insn;
- bitmap_copy (&c->live_throughout, live_relevant_regs);
- }
- insn = PREV_INSN (insn);
- }
- }
-
- reload_insn_chain = c;
- *p = NULL;
-
- for (i = 0; i < (unsigned int) max_regno; i++)
- if (live_subregs[i] != NULL)
- sbitmap_free (live_subregs[i]);
- free (live_subregs);
-
- if (dump_file)
- print_insn_chains (dump_file);
-}
-
-/* Examine the rtx found in *LOC, which is read or written to as determined
- by TYPE. Return false if we find a reason why an insn containing this
- rtx should not be moved (such as accesses to non-constant memory), true
- otherwise. */
-static bool
-rtx_moveable_p (rtx *loc, enum op_type type)
-{
- const char *fmt;
- rtx x = *loc;
- int i, j;
-
- enum rtx_code code = GET_CODE (x);
- switch (code)
- {
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- return true;
-
- case PC:
- return type == OP_IN;
-
- case REG:
- if (x == frame_pointer_rtx)
- return true;
- if (HARD_REGISTER_P (x))
- return false;
-
- return true;
-
- case MEM:
- if (type == OP_IN && MEM_READONLY_P (x))
- return rtx_moveable_p (&XEXP (x, 0), OP_IN);
- return false;
-
- case SET:
- return (rtx_moveable_p (&SET_SRC (x), OP_IN)
- && rtx_moveable_p (&SET_DEST (x), OP_OUT));
-
- case STRICT_LOW_PART:
- return rtx_moveable_p (&XEXP (x, 0), OP_OUT);
-
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- return (rtx_moveable_p (&XEXP (x, 0), type)
- && rtx_moveable_p (&XEXP (x, 1), OP_IN)
- && rtx_moveable_p (&XEXP (x, 2), OP_IN));
-
- case CLOBBER:
- return rtx_moveable_p (&SET_DEST (x), OP_OUT);
-
- case UNSPEC_VOLATILE:
- /* It is a bad idea to consider insns with such rtl
- as moveable ones. The insn scheduler also considers them as barrier
- for a reason. */
- return false;
-
- case ASM_OPERANDS:
- /* The same is true for volatile asm: it has unknown side effects, it
- cannot be moved at will. */
- if (MEM_VOLATILE_P (x))
- return false;
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (!rtx_moveable_p (&XEXP (x, i), type))
- return false;
- }
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- {
- if (!rtx_moveable_p (&XVECEXP (x, i, j), type))
- return false;
- }
- }
- return true;
-}
-
-/* A wrapper around dominated_by_p, which uses the information in UID_LUID
- to give dominance relationships between two insns I1 and I2. */
-static bool
-insn_dominated_by_p (rtx i1, rtx i2, int *uid_luid)
-{
- basic_block bb1 = BLOCK_FOR_INSN (i1);
- basic_block bb2 = BLOCK_FOR_INSN (i2);
-
- if (bb1 == bb2)
- return uid_luid[INSN_UID (i2)] < uid_luid[INSN_UID (i1)];
- return dominated_by_p (CDI_DOMINATORS, bb1, bb2);
-}
-
-/* Record the range of register numbers added by find_moveable_pseudos. */
-int first_moveable_pseudo, last_moveable_pseudo;
-
-/* These two vectors hold data for every register added by
- find_movable_pseudos, with index 0 holding data for the
- first_moveable_pseudo. */
-/* The original home register. */
-static vec<rtx> pseudo_replaced_reg;
-
-/* Look for instances where we have an instruction that is known to increase
- register pressure, and whose result is not used immediately. If it is
- possible to move the instruction downwards to just before its first use,
- split its lifetime into two ranges. We create a new pseudo to compute the
- value, and emit a move instruction just before the first use. If, after
- register allocation, the new pseudo remains unallocated, the function
- move_unallocated_pseudos then deletes the move instruction and places
- the computation just before the first use.
-
- Such a move is safe and profitable if all the input registers remain live
- and unchanged between the original computation and its first use. In such
- a situation, the computation is known to increase register pressure, and
- moving it is known to at least not worsen it.
-
- We restrict moves to only those cases where a register remains unallocated,
- in order to avoid interfering too much with the instruction schedule. As
- an exception, we may move insns which only modify their input register
- (typically induction variables), as this increases the freedom for our
- intended transformation, and does not limit the second instruction
- scheduler pass. */
-
-static void
-find_moveable_pseudos (void)
-{
- unsigned i;
- int max_regs = max_reg_num ();
- int max_uid = get_max_uid ();
- basic_block bb;
- int *uid_luid = XNEWVEC (int, max_uid);
- rtx_insn **closest_uses = XNEWVEC (rtx_insn *, max_regs);
- /* A set of registers which are live but not modified throughout a block. */
- bitmap_head *bb_transp_live = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- /* A set of registers which only exist in a given basic block. */
- bitmap_head *bb_local = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- /* A set of registers which are set once, in an instruction that can be
- moved freely downwards, but are otherwise transparent to a block. */
- bitmap_head *bb_moveable_reg_sets = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- auto_bitmap live, used, set, interesting, unusable_as_input;
- bitmap_iterator bi;
-
- first_moveable_pseudo = max_regs;
- pseudo_replaced_reg.release ();
- pseudo_replaced_reg.safe_grow_cleared (max_regs, true);
-
- df_analyze ();
- calculate_dominance_info (CDI_DOMINATORS);
-
- i = 0;
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
- bitmap transp = bb_transp_live + bb->index;
- bitmap moveable = bb_moveable_reg_sets + bb->index;
- bitmap local = bb_local + bb->index;
-
- bitmap_initialize (local, 0);
- bitmap_initialize (transp, 0);
- bitmap_initialize (moveable, 0);
- bitmap_copy (live, df_get_live_out (bb));
- bitmap_and_into (live, df_get_live_in (bb));
- bitmap_copy (transp, live);
- bitmap_clear (moveable);
- bitmap_clear (live);
- bitmap_clear (used);
- bitmap_clear (set);
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- {
- df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- df_ref def, use;
-
- uid_luid[INSN_UID (insn)] = i++;
-
- def = df_single_def (insn_info);
- use = df_single_use (insn_info);
- if (use
- && def
- && DF_REF_REGNO (use) == DF_REF_REGNO (def)
- && !bitmap_bit_p (set, DF_REF_REGNO (use))
- && rtx_moveable_p (&PATTERN (insn), OP_IN))
- {
- unsigned regno = DF_REF_REGNO (use);
- bitmap_set_bit (moveable, regno);
- bitmap_set_bit (set, regno);
- bitmap_set_bit (used, regno);
- bitmap_clear_bit (transp, regno);
- continue;
- }
- FOR_EACH_INSN_INFO_USE (use, insn_info)
- {
- unsigned regno = DF_REF_REGNO (use);
- bitmap_set_bit (used, regno);
- if (bitmap_clear_bit (moveable, regno))
- bitmap_clear_bit (transp, regno);
- }
-
- FOR_EACH_INSN_INFO_DEF (def, insn_info)
- {
- unsigned regno = DF_REF_REGNO (def);
- bitmap_set_bit (set, regno);
- bitmap_clear_bit (transp, regno);
- bitmap_clear_bit (moveable, regno);
- }
- }
- }
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap local = bb_local + bb->index;
- rtx_insn *insn;
-
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- {
- df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- rtx_insn *def_insn;
- rtx closest_use, note;
- df_ref def, use;
- unsigned regno;
- bool all_dominated, all_local;
- machine_mode mode;
-
- def = df_single_def (insn_info);
- /* There must be exactly one def in this insn. */
- if (!def || !single_set (insn))
- continue;
- /* This must be the only definition of the reg. We also limit
- which modes we deal with so that we can assume we can generate
- move instructions. */
- regno = DF_REF_REGNO (def);
- mode = GET_MODE (DF_REF_REG (def));
- if (DF_REG_DEF_COUNT (regno) != 1
- || !DF_REF_INSN_INFO (def)
- || HARD_REGISTER_NUM_P (regno)
- || DF_REG_EQ_USE_COUNT (regno) > 0
- || (!INTEGRAL_MODE_P (mode)
- && !FLOAT_MODE_P (mode)
- && !OPAQUE_MODE_P (mode)))
- continue;
- def_insn = DF_REF_INSN (def);
-
- for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_EQUIV && MEM_P (XEXP (note, 0)))
- break;
-
- if (note)
- {
- if (dump_file)
- fprintf (dump_file, "Ignoring reg %d, has equiv memory\n",
- regno);
- bitmap_set_bit (unusable_as_input, regno);
- continue;
- }
-
- use = DF_REG_USE_CHAIN (regno);
- all_dominated = true;
- all_local = true;
- closest_use = NULL_RTX;
- for (; use; use = DF_REF_NEXT_REG (use))
- {
- rtx_insn *insn;
- if (!DF_REF_INSN_INFO (use))
- {
- all_dominated = false;
- all_local = false;
- break;
- }
- insn = DF_REF_INSN (use);
- if (DEBUG_INSN_P (insn))
- continue;
- if (BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (def_insn))
- all_local = false;
- if (!insn_dominated_by_p (insn, def_insn, uid_luid))
- all_dominated = false;
- if (closest_use != insn && closest_use != const0_rtx)
- {
- if (closest_use == NULL_RTX)
- closest_use = insn;
- else if (insn_dominated_by_p (closest_use, insn, uid_luid))
- closest_use = insn;
- else if (!insn_dominated_by_p (insn, closest_use, uid_luid))
- closest_use = const0_rtx;
- }
- }
- if (!all_dominated)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d not all uses dominated by set\n",
- regno);
- continue;
- }
- if (all_local)
- bitmap_set_bit (local, regno);
- if (closest_use == const0_rtx || closest_use == NULL
- || next_nonnote_nondebug_insn (def_insn) == closest_use)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d uninteresting%s\n", regno,
- closest_use == const0_rtx || closest_use == NULL
- ? " (no unique first use)" : "");
- continue;
- }
-
- bitmap_set_bit (interesting, regno);
- /* If we get here, we know closest_use is a non-NULL insn
- (as opposed to const_0_rtx). */
- closest_uses[regno] = as_a <rtx_insn *> (closest_use);
-
- if (dump_file && (all_local || all_dominated))
- {
- fprintf (dump_file, "Reg %u:", regno);
- if (all_local)
- fprintf (dump_file, " local to bb %d", bb->index);
- if (all_dominated)
- fprintf (dump_file, " def dominates all uses");
- if (closest_use != const0_rtx)
- fprintf (dump_file, " has unique first use");
- fputs ("\n", dump_file);
- }
- }
- }
-
- EXECUTE_IF_SET_IN_BITMAP (interesting, 0, i, bi)
- {
- df_ref def = DF_REG_DEF_CHAIN (i);
- rtx_insn *def_insn = DF_REF_INSN (def);
- basic_block def_block = BLOCK_FOR_INSN (def_insn);
- bitmap def_bb_local = bb_local + def_block->index;
- bitmap def_bb_moveable = bb_moveable_reg_sets + def_block->index;
- bitmap def_bb_transp = bb_transp_live + def_block->index;
- bool local_to_bb_p = bitmap_bit_p (def_bb_local, i);
- rtx_insn *use_insn = closest_uses[i];
- df_ref use;
- bool all_ok = true;
- bool all_transp = true;
-
- if (!REG_P (DF_REF_REG (def)))
- continue;
-
- if (!local_to_bb_p)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %u not local to one basic block\n",
- i);
- continue;
- }
- if (reg_equiv_init (i) != NULL_RTX)
- {
- if (dump_file)
- fprintf (dump_file, "Ignoring reg %u with equiv init insn\n",
- i);
- continue;
- }
- if (!rtx_moveable_p (&PATTERN (def_insn), OP_IN))
- {
- if (dump_file)
- fprintf (dump_file, "Found def insn %d for %d to be not moveable\n",
- INSN_UID (def_insn), i);
- continue;
- }
- if (dump_file)
- fprintf (dump_file, "Examining insn %d, def for %d\n",
- INSN_UID (def_insn), i);
- FOR_EACH_INSN_USE (use, def_insn)
- {
- unsigned regno = DF_REF_REGNO (use);
- if (bitmap_bit_p (unusable_as_input, regno))
- {
- all_ok = false;
- if (dump_file)
- fprintf (dump_file, " found unusable input reg %u.\n", regno);
- break;
- }
- if (!bitmap_bit_p (def_bb_transp, regno))
- {
- if (bitmap_bit_p (def_bb_moveable, regno)
- && !control_flow_insn_p (use_insn))
- {
- if (modified_between_p (DF_REF_REG (use), def_insn, use_insn))
- {
- rtx_insn *x = NEXT_INSN (def_insn);
- while (!modified_in_p (DF_REF_REG (use), x))
- {
- gcc_assert (x != use_insn);
- x = NEXT_INSN (x);
- }
- if (dump_file)
- fprintf (dump_file, " input reg %u modified but insn %d moveable\n",
- regno, INSN_UID (x));
- emit_insn_after (PATTERN (x), use_insn);
- set_insn_deleted (x);
- }
- else
- {
- if (dump_file)
- fprintf (dump_file, " input reg %u modified between def and use\n",
- regno);
- all_transp = false;
- }
- }
- else
- all_transp = false;
- }
- }
- if (!all_ok)
- continue;
- if (!dbg_cnt (ira_move))
- break;
- if (dump_file)
- fprintf (dump_file, " all ok%s\n", all_transp ? " and transp" : "");
-
- if (all_transp)
- {
- rtx def_reg = DF_REF_REG (def);
- rtx newreg = ira_create_new_reg (def_reg);
- if (validate_change (def_insn, DF_REF_REAL_LOC (def), newreg, 0))
- {
- unsigned nregno = REGNO (newreg);
- emit_insn_before (gen_move_insn (def_reg, newreg), use_insn);
- nregno -= max_regs;
- pseudo_replaced_reg[nregno] = def_reg;
- }
- }
- }
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap_clear (bb_local + bb->index);
- bitmap_clear (bb_transp_live + bb->index);
- bitmap_clear (bb_moveable_reg_sets + bb->index);
- }
- free (uid_luid);
- free (closest_uses);
- free (bb_local);
- free (bb_transp_live);
- free (bb_moveable_reg_sets);
-
- last_moveable_pseudo = max_reg_num ();
-
- fix_reg_equiv_init ();
- expand_reg_info ();
- regstat_free_n_sets_and_refs ();
- regstat_free_ri ();
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
- free_dominance_info (CDI_DOMINATORS);
-}
-
-/* If SET pattern SET is an assignment from a hard register to a pseudo which
- is live at CALL_DOM (if non-NULL, otherwise this check is omitted), return
- the destination. Otherwise return NULL. */
-
-static rtx
-interesting_dest_for_shprep_1 (rtx set, basic_block call_dom)
-{
- rtx src = SET_SRC (set);
- rtx dest = SET_DEST (set);
- if (!REG_P (src) || !HARD_REGISTER_P (src)
- || !REG_P (dest) || HARD_REGISTER_P (dest)
- || (call_dom && !bitmap_bit_p (df_get_live_in (call_dom), REGNO (dest))))
- return NULL;
- return dest;
-}
-
-/* If insn is interesting for parameter range-splitting shrink-wrapping
- preparation, i.e. it is a single set from a hard register to a pseudo, which
- is live at CALL_DOM (if non-NULL, otherwise this check is omitted), or a
- parallel statement with only one such statement, return the destination.
- Otherwise return NULL. */
-
-static rtx
-interesting_dest_for_shprep (rtx_insn *insn, basic_block call_dom)
-{
- if (!INSN_P (insn))
- return NULL;
- rtx pat = PATTERN (insn);
- if (GET_CODE (pat) == SET)
- return interesting_dest_for_shprep_1 (pat, call_dom);
-
- if (GET_CODE (pat) != PARALLEL)
- return NULL;
- rtx ret = NULL;
- for (int i = 0; i < XVECLEN (pat, 0); i++)
- {
- rtx sub = XVECEXP (pat, 0, i);
- if (GET_CODE (sub) == USE || GET_CODE (sub) == CLOBBER)
- continue;
- if (GET_CODE (sub) != SET
- || side_effects_p (sub))
- return NULL;
- rtx dest = interesting_dest_for_shprep_1 (sub, call_dom);
- if (dest && ret)
- return NULL;
- if (dest)
- ret = dest;
- }
- return ret;
-}
-
-/* Split live ranges of pseudos that are loaded from hard registers in the
- first BB in a BB that dominates all non-sibling call if such a BB can be
- found and is not in a loop. Return true if the function has made any
- changes. */
-
-static bool
-split_live_ranges_for_shrink_wrap (void)
-{
- basic_block bb, call_dom = NULL;
- basic_block first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
- rtx_insn *insn, *last_interesting_insn = NULL;
- auto_bitmap need_new, reachable;
- vec<basic_block> queue;
-
- if (!SHRINK_WRAPPING_ENABLED)
- return false;
-
- queue.create (n_basic_blocks_for_fn (cfun));
-
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- if (CALL_P (insn) && !SIBLING_CALL_P (insn))
- {
- if (bb == first)
- {
- queue.release ();
- return false;
- }
-
- bitmap_set_bit (need_new, bb->index);
- bitmap_set_bit (reachable, bb->index);
- queue.quick_push (bb);
- break;
- }
-
- if (queue.is_empty ())
- {
- queue.release ();
- return false;
- }
-
- while (!queue.is_empty ())
- {
- edge e;
- edge_iterator ei;
-
- bb = queue.pop ();
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
- && bitmap_set_bit (reachable, e->dest->index))
- queue.quick_push (e->dest);
- }
- queue.release ();
-
- FOR_BB_INSNS (first, insn)
- {
- rtx dest = interesting_dest_for_shprep (insn, NULL);
- if (!dest)
- continue;
-
- if (DF_REG_DEF_COUNT (REGNO (dest)) > 1)
- return false;
-
- for (df_ref use = DF_REG_USE_CHAIN (REGNO(dest));
- use;
- use = DF_REF_NEXT_REG (use))
- {
- int ubbi = DF_REF_BB (use)->index;
- if (bitmap_bit_p (reachable, ubbi))
- bitmap_set_bit (need_new, ubbi);
- }
- last_interesting_insn = insn;
- }
-
- if (!last_interesting_insn)
- return false;
-
- call_dom = nearest_common_dominator_for_set (CDI_DOMINATORS, need_new);
- if (call_dom == first)
- return false;
-
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
- while (bb_loop_depth (call_dom) > 0)
- call_dom = get_immediate_dominator (CDI_DOMINATORS, call_dom);
- loop_optimizer_finalize ();
-
- if (call_dom == first)
- return false;
-
- calculate_dominance_info (CDI_POST_DOMINATORS);
- if (dominated_by_p (CDI_POST_DOMINATORS, first, call_dom))
- {
- free_dominance_info (CDI_POST_DOMINATORS);
- return false;
- }
- free_dominance_info (CDI_POST_DOMINATORS);
-
- if (dump_file)
- fprintf (dump_file, "Will split live ranges of parameters at BB %i\n",
- call_dom->index);
-
- bool ret = false;
- FOR_BB_INSNS (first, insn)
- {
- rtx dest = interesting_dest_for_shprep (insn, call_dom);
- if (!dest || dest == pic_offset_table_rtx)
- continue;
-
- bool need_newreg = false;
- df_ref use, next;
- for (use = DF_REG_USE_CHAIN (REGNO (dest)); use; use = next)
- {
- rtx_insn *uin = DF_REF_INSN (use);
- next = DF_REF_NEXT_REG (use);
-
- if (DEBUG_INSN_P (uin))
- continue;
-
- basic_block ubb = BLOCK_FOR_INSN (uin);
- if (ubb == call_dom
- || dominated_by_p (CDI_DOMINATORS, ubb, call_dom))
- {
- need_newreg = true;
- break;
- }
- }
-
- if (need_newreg)
- {
- rtx newreg = ira_create_new_reg (dest);
-
- for (use = DF_REG_USE_CHAIN (REGNO (dest)); use; use = next)
- {
- rtx_insn *uin = DF_REF_INSN (use);
- next = DF_REF_NEXT_REG (use);
-
- basic_block ubb = BLOCK_FOR_INSN (uin);
- if (ubb == call_dom
- || dominated_by_p (CDI_DOMINATORS, ubb, call_dom))
- validate_change (uin, DF_REF_REAL_LOC (use), newreg, true);
- }
-
- rtx_insn *new_move = gen_move_insn (newreg, dest);
- emit_insn_after (new_move, bb_note (call_dom));
- if (dump_file)
- {
- fprintf (dump_file, "Split live-range of register ");
- print_rtl_single (dump_file, dest);
- }
- ret = true;
- }
-
- if (insn == last_interesting_insn)
- break;
- }
- apply_change_group ();
- return ret;
-}
-
-/* Perform the second half of the transformation started in
- find_moveable_pseudos. We look for instances where the newly introduced
- pseudo remains unallocated, and remove it by moving the definition to
- just before its use, replacing the move instruction generated by
- find_moveable_pseudos. */
-static void
-move_unallocated_pseudos (void)
-{
- int i;
- for (i = first_moveable_pseudo; i < last_moveable_pseudo; i++)
- if (reg_renumber[i] < 0)
- {
- int idx = i - first_moveable_pseudo;
- rtx other_reg = pseudo_replaced_reg[idx];
- /* The iterating range [first_moveable_pseudo, last_moveable_pseudo)
- covers every new pseudo created in find_moveable_pseudos,
- regardless of the validation with it is successful or not.
- So we need to skip the pseudos which were used in those failed
- validations to avoid unexpected DF info and consequent ICE.
- We only set pseudo_replaced_reg[] when the validation is successful
- in find_moveable_pseudos, it's enough to check it here. */
- if (!other_reg)
- continue;
- rtx_insn *def_insn = DF_REF_INSN (DF_REG_DEF_CHAIN (i));
- /* The use must follow all definitions of OTHER_REG, so we can
- insert the new definition immediately after any of them. */
- df_ref other_def = DF_REG_DEF_CHAIN (REGNO (other_reg));
- rtx_insn *move_insn = DF_REF_INSN (other_def);
- rtx_insn *newinsn = emit_insn_after (PATTERN (def_insn), move_insn);
- rtx set;
- int success;
-
- if (dump_file)
- fprintf (dump_file, "moving def of %d (insn %d now) ",
- REGNO (other_reg), INSN_UID (def_insn));
-
- delete_insn (move_insn);
- while ((other_def = DF_REG_DEF_CHAIN (REGNO (other_reg))))
- delete_insn (DF_REF_INSN (other_def));
- delete_insn (def_insn);
-
- set = single_set (newinsn);
- success = validate_change (newinsn, &SET_DEST (set), other_reg, 0);
- gcc_assert (success);
- if (dump_file)
- fprintf (dump_file, " %d) rather than keep unallocated replacement %d\n",
- INSN_UID (newinsn), i);
- SET_REG_N_REFS (i, 0);
- }
-
- first_moveable_pseudo = last_moveable_pseudo = 0;
-}
-
-
-
-/* Code dealing with scratches (changing them onto
- pseudos and restoring them from the pseudos).
-
- We change scratches into pseudos at the beginning of IRA to
- simplify dealing with them (conflicts, hard register assignments).
-
- If the pseudo denoting scratch was spilled it means that we do not
- need a hard register for it. Such pseudos are transformed back to
- scratches at the end of LRA. */
-
-/* Description of location of a former scratch operand. */
-struct sloc
-{
- rtx_insn *insn; /* Insn where the scratch was. */
- int nop; /* Number of the operand which was a scratch. */
- unsigned regno; /* regno gnerated instead of scratch */
- int icode; /* Original icode from which scratch was removed. */
-};
-
-typedef struct sloc *sloc_t;
-
-/* Locations of the former scratches. */
-static vec<sloc_t> scratches;
-
-/* Bitmap of scratch regnos. */
-static bitmap_head scratch_bitmap;
-
-/* Bitmap of scratch operands. */
-static bitmap_head scratch_operand_bitmap;
-
-/* Return true if pseudo REGNO is made of SCRATCH. */
-bool
-ira_former_scratch_p (int regno)
-{
- return bitmap_bit_p (&scratch_bitmap, regno);
-}
-
-/* Return true if the operand NOP of INSN is a former scratch. */
-bool
-ira_former_scratch_operand_p (rtx_insn *insn, int nop)
-{
- return bitmap_bit_p (&scratch_operand_bitmap,
- INSN_UID (insn) * MAX_RECOG_OPERANDS + nop) != 0;
-}
-
-/* Register operand NOP in INSN as a former scratch. It will be
- changed to scratch back, if it is necessary, at the LRA end. */
-void
-ira_register_new_scratch_op (rtx_insn *insn, int nop, int icode)
-{
- rtx op = *recog_data.operand_loc[nop];
- sloc_t loc = XNEW (struct sloc);
- ira_assert (REG_P (op));
- loc->insn = insn;
- loc->nop = nop;
- loc->regno = REGNO (op);
- loc->icode = icode;
- scratches.safe_push (loc);
- bitmap_set_bit (&scratch_bitmap, REGNO (op));
- bitmap_set_bit (&scratch_operand_bitmap,
- INSN_UID (insn) * MAX_RECOG_OPERANDS + nop);
- add_reg_note (insn, REG_UNUSED, op);
-}
-
-/* Return true if string STR contains constraint 'X'. */
-static bool
-contains_X_constraint_p (const char *str)
-{
- int c;
-
- while ((c = *str))
- {
- str += CONSTRAINT_LEN (c, str);
- if (c == 'X') return true;
- }
- return false;
-}
-
-/* Change INSN's scratches into pseudos and save their location.
- Return true if we changed any scratch. */
-bool
-ira_remove_insn_scratches (rtx_insn *insn, bool all_p, FILE *dump_file,
- rtx (*get_reg) (rtx original))
-{
- int i;
- bool insn_changed_p;
- rtx reg, *loc;
-
- extract_insn (insn);
- insn_changed_p = false;
- for (i = 0; i < recog_data.n_operands; i++)
- {
- loc = recog_data.operand_loc[i];
- if (GET_CODE (*loc) == SCRATCH && GET_MODE (*loc) != VOIDmode)
- {
- if (! all_p && contains_X_constraint_p (recog_data.constraints[i]))
- continue;
- insn_changed_p = true;
- *loc = reg = get_reg (*loc);
- ira_register_new_scratch_op (insn, i, INSN_CODE (insn));
- if (ira_dump_file != NULL)
- fprintf (dump_file,
- "Removing SCRATCH to p%u in insn #%u (nop %d)\n",
- REGNO (reg), INSN_UID (insn), i);
- }
- }
- return insn_changed_p;
-}
-
-/* Return new register of the same mode as ORIGINAL. Used in
- remove_scratches. */
-static rtx
-get_scratch_reg (rtx original)
-{
- return gen_reg_rtx (GET_MODE (original));
-}
-
-/* Change scratches into pseudos and save their location. Return true
- if we changed any scratch. */
-static bool
-remove_scratches (void)
-{
- bool change_p = false;
- basic_block bb;
- rtx_insn *insn;
-
- scratches.create (get_max_uid ());
- bitmap_initialize (&scratch_bitmap, &reg_obstack);
- bitmap_initialize (&scratch_operand_bitmap, &reg_obstack);
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- if (INSN_P (insn)
- && ira_remove_insn_scratches (insn, false, ira_dump_file, get_scratch_reg))
- {
- /* Because we might use DF, we need to keep DF info up to date. */
- df_insn_rescan (insn);
- change_p = true;
- }
- return change_p;
-}
-
-/* Changes pseudos created by function remove_scratches onto scratches. */
-void
-ira_restore_scratches (FILE *dump_file)
-{
- int regno, n;
- unsigned i;
- rtx *op_loc;
- sloc_t loc;
-
- for (i = 0; scratches.iterate (i, &loc); i++)
- {
- /* Ignore already deleted insns. */
- if (NOTE_P (loc->insn)
- && NOTE_KIND (loc->insn) == NOTE_INSN_DELETED)
- continue;
- extract_insn (loc->insn);
- if (loc->icode != INSN_CODE (loc->insn))
- {
- /* The icode doesn't match, which means the insn has been modified
- (e.g. register elimination). The scratch cannot be restored. */
- continue;
- }
- op_loc = recog_data.operand_loc[loc->nop];
- if (REG_P (*op_loc)
- && ((regno = REGNO (*op_loc)) >= FIRST_PSEUDO_REGISTER)
- && reg_renumber[regno] < 0)
- {
- /* It should be only case when scratch register with chosen
- constraint 'X' did not get memory or hard register. */
- ira_assert (ira_former_scratch_p (regno));
- *op_loc = gen_rtx_SCRATCH (GET_MODE (*op_loc));
- for (n = 0; n < recog_data.n_dups; n++)
- *recog_data.dup_loc[n]
- = *recog_data.operand_loc[(int) recog_data.dup_num[n]];
- if (dump_file != NULL)
- fprintf (dump_file, "Restoring SCRATCH in insn #%u(nop %d)\n",
- INSN_UID (loc->insn), loc->nop);
- }
- }
- for (i = 0; scratches.iterate (i, &loc); i++)
- free (loc);
- scratches.release ();
- bitmap_clear (&scratch_bitmap);
- bitmap_clear (&scratch_operand_bitmap);
-}
-
-
-
-/* If the backend knows where to allocate pseudos for hard
- register initial values, register these allocations now. */
-static void
-allocate_initial_values (void)
-{
- if (targetm.allocate_initial_value)
- {
- rtx hreg, preg, x;
- int i, regno;
-
- for (i = 0; HARD_REGISTER_NUM_P (i); i++)
- {
- if (! initial_value_entry (i, &hreg, &preg))
- break;
-
- x = targetm.allocate_initial_value (hreg);
- regno = REGNO (preg);
- if (x && REG_N_SETS (regno) <= 1)
- {
- if (MEM_P (x))
- reg_equiv_memory_loc (regno) = x;
- else
- {
- basic_block bb;
- int new_regno;
-
- gcc_assert (REG_P (x));
- new_regno = REGNO (x);
- reg_renumber[regno] = new_regno;
- /* Poke the regno right into regno_reg_rtx so that even
- fixed regs are accepted. */
- SET_REGNO (preg, new_regno);
- /* Update global register liveness information. */
- FOR_EACH_BB_FN (bb, cfun)
- {
- if (REGNO_REG_SET_P (df_get_live_in (bb), regno))
- SET_REGNO_REG_SET (df_get_live_in (bb), new_regno);
- if (REGNO_REG_SET_P (df_get_live_out (bb), regno))
- SET_REGNO_REG_SET (df_get_live_out (bb), new_regno);
- }
- }
- }
- }
-
- gcc_checking_assert (! initial_value_entry (FIRST_PSEUDO_REGISTER,
- &hreg, &preg));
- }
-}
-
-
-
-
-/* True when we use LRA instead of reload pass for the current
- function. */
-bool ira_use_lra_p;
-
-/* True if we have allocno conflicts. It is false for non-optimized
- mode or when the conflict table is too big. */
-bool ira_conflicts_p;
-
-/* Saved between IRA and reload. */
-static int saved_flag_ira_share_spill_slots;
-
-/* This is the main entry of IRA. */
-static void
-ira (FILE *f)
-{
- bool loops_p;
- int ira_max_point_before_emit;
- bool saved_flag_caller_saves = flag_caller_saves;
- enum ira_region saved_flag_ira_region = flag_ira_region;
- basic_block bb;
- edge_iterator ei;
- edge e;
- bool output_jump_reload_p = false;
-
- if (ira_use_lra_p)
- {
- /* First put potential jump output reloads on the output edges
- as USE which will be removed at the end of LRA. The major
- goal is actually to create BBs for critical edges for LRA and
- populate them later by live info. In LRA it will be
- difficult to do this. */
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *end = BB_END (bb);
- if (!JUMP_P (end))
- continue;
- extract_insn (end);
- for (int i = 0; i < recog_data.n_operands; i++)
- if (recog_data.operand_type[i] != OP_IN)
- {
- bool skip_p = false;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (EDGE_CRITICAL_P (e)
- && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
- && (e->flags & EDGE_ABNORMAL))
- {
- skip_p = true;
- break;
- }
- if (skip_p)
- break;
- output_jump_reload_p = true;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (EDGE_CRITICAL_P (e)
- && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
- {
- start_sequence ();
- /* We need to put some no-op insn here. We can
- not put a note as commit_edges insertion will
- fail. */
- emit_insn (gen_rtx_USE (VOIDmode, const1_rtx));
- rtx_insn *insns = get_insns ();
- end_sequence ();
- insert_insn_on_edge (insns, e);
- }
- break;
- }
- }
- if (output_jump_reload_p)
- commit_edge_insertions ();
- }
-
- if (flag_ira_verbose < 10)
- {
- internal_flag_ira_verbose = flag_ira_verbose;
- ira_dump_file = f;
- }
- else
- {
- internal_flag_ira_verbose = flag_ira_verbose - 10;
- ira_dump_file = stderr;
- }
-
- clear_bb_flags ();
-
- /* Determine if the current function is a leaf before running IRA
- since this can impact optimizations done by the prologue and
- epilogue thus changing register elimination offsets.
- Other target callbacks may use crtl->is_leaf too, including
- SHRINK_WRAPPING_ENABLED, so initialize as early as possible. */
- crtl->is_leaf = leaf_function_p ();
-
- /* Perform target specific PIC register initialization. */
- targetm.init_pic_reg ();
-
- ira_conflicts_p = optimize > 0;
-
- /* Determine the number of pseudos actually requiring coloring. */
- unsigned int num_used_regs = 0;
- for (unsigned int i = FIRST_PSEUDO_REGISTER; i < DF_REG_SIZE (df); i++)
- if (DF_REG_DEF_COUNT (i) || DF_REG_USE_COUNT (i))
- num_used_regs++;
-
- /* If there are too many pseudos and/or basic blocks (e.g. 10K
- pseudos and 10K blocks or 100K pseudos and 1K blocks), we will
- use simplified and faster algorithms in LRA. */
- lra_simple_p
- = ira_use_lra_p
- && num_used_regs >= (1U << 26) / last_basic_block_for_fn (cfun);
-
- if (lra_simple_p)
- {
- /* It permits to skip live range splitting in LRA. */
- flag_caller_saves = false;
- /* There is no sense to do regional allocation when we use
- simplified LRA. */
- flag_ira_region = IRA_REGION_ONE;
- ira_conflicts_p = false;
- }
-
-#ifndef IRA_NO_OBSTACK
- gcc_obstack_init (&ira_obstack);
-#endif
- bitmap_obstack_initialize (&ira_bitmap_obstack);
-
- /* LRA uses its own infrastructure to handle caller save registers. */
- if (flag_caller_saves && !ira_use_lra_p)
- init_caller_save ();
-
- setup_prohibited_mode_move_regs ();
- decrease_live_ranges_number ();
- df_note_add_problem ();
-
- /* DF_LIVE can't be used in the register allocator, too many other
- parts of the compiler depend on using the "classic" liveness
- interpretation of the DF_LR problem. See PR38711.
- Remove the problem, so that we don't spend time updating it in
- any of the df_analyze() calls during IRA/LRA. */
- if (optimize > 1)
- df_remove_problem (df_live);
- gcc_checking_assert (df_live == NULL);
-
- if (flag_checking)
- df->changeable_flags |= DF_VERIFY_SCHEDULED;
-
- df_analyze ();
-
- init_reg_equiv ();
- if (ira_conflicts_p)
- {
- calculate_dominance_info (CDI_DOMINATORS);
-
- if (split_live_ranges_for_shrink_wrap ())
- df_analyze ();
-
- free_dominance_info (CDI_DOMINATORS);
- }
-
- df_clear_flags (DF_NO_INSN_RESCAN);
-
- indirect_jump_optimize ();
- if (delete_trivially_dead_insns (get_insns (), max_reg_num ()))
- df_analyze ();
-
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
-
- /* If we are not optimizing, then this is the only place before
- register allocation where dataflow is done. And that is needed
- to generate these warnings. */
- if (warn_clobbered)
- generate_setjmp_warnings ();
-
- /* update_equiv_regs can use reg classes of pseudos and they are set up in
- register pressure sensitive scheduling and loop invariant motion and in
- live range shrinking. This info can become obsolete if we add new pseudos
- since the last set up. Recalculate it again if the new pseudos were
- added. */
- if (resize_reg_info () && (flag_sched_pressure || flag_live_range_shrinkage
- || flag_ira_loop_pressure))
- ira_set_pseudo_classes (true, ira_dump_file);
-
- init_alias_analysis ();
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
- reg_equiv = XCNEWVEC (struct equivalence, max_reg_num ());
- update_equiv_regs_prescan ();
- update_equiv_regs ();
-
- /* Don't move insns if live range shrinkage or register
- pressure-sensitive scheduling were done because it will not
- improve allocation but likely worsen insn scheduling. */
- if (optimize
- && !flag_live_range_shrinkage
- && !(flag_sched_pressure && flag_schedule_insns))
- combine_and_move_insns ();
-
- /* Gather additional equivalences with memory. */
- if (optimize)
- add_store_equivs ();
-
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- end_alias_analysis ();
- free (reg_equiv);
-
- /* Once max_regno changes, we need to free and re-init/re-compute
- some data structures like regstat_n_sets_and_refs and reg_info_p. */
- auto regstat_recompute_for_max_regno = []() {
- regstat_free_n_sets_and_refs ();
- regstat_free_ri ();
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
- };
-
- int max_regno_before_rm = max_reg_num ();
- if (ira_use_lra_p && remove_scratches ())
- {
- ira_expand_reg_equiv ();
- /* For now remove_scatches is supposed to create pseudos when it
- succeeds, assert this happens all the time. Once it doesn't
- hold, we should guard the regstat recompute for the case
- max_regno changes. */
- gcc_assert (max_regno_before_rm != max_reg_num ());
- regstat_recompute_for_max_regno ();
- }
-
- setup_reg_equiv ();
- grow_reg_equivs ();
- setup_reg_equiv_init ();
-
- allocated_reg_info_size = max_reg_num ();
-
- /* It is not worth to do such improvement when we use a simple
- allocation because of -O0 usage or because the function is too
- big. */
- if (ira_conflicts_p)
- find_moveable_pseudos ();
-
- max_regno_before_ira = max_reg_num ();
- ira_setup_eliminable_regset ();
-
- ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
- ira_load_cost = ira_store_cost = ira_shuffle_cost = 0;
- ira_move_loops_num = ira_additional_jumps_num = 0;
-
- ira_assert (current_loops == NULL);
- if (flag_ira_region == IRA_REGION_ALL || flag_ira_region == IRA_REGION_MIXED)
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS | LOOPS_HAVE_RECORDED_EXITS);
-
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- fprintf (ira_dump_file, "Building IRA IR\n");
- loops_p = ira_build ();
-
- ira_assert (ira_conflicts_p || !loops_p);
-
- saved_flag_ira_share_spill_slots = flag_ira_share_spill_slots;
- if (too_high_register_pressure_p () || cfun->calls_setjmp)
- /* It is just wasting compiler's time to pack spilled pseudos into
- stack slots in this case -- prohibit it. We also do this if
- there is setjmp call because a variable not modified between
- setjmp and longjmp the compiler is required to preserve its
- value and sharing slots does not guarantee it. */
- flag_ira_share_spill_slots = FALSE;
-
- ira_color ();
-
- ira_max_point_before_emit = ira_max_point;
-
- ira_initiate_emit_data ();
-
- ira_emit (loops_p);
-
- max_regno = max_reg_num ();
- if (ira_conflicts_p)
- {
- if (! loops_p)
- {
- if (! ira_use_lra_p)
- ira_initiate_assign ();
- }
- else
- {
- expand_reg_info ();
-
- if (ira_use_lra_p)
- {
- ira_allocno_t a;
- ira_allocno_iterator ai;
-
- FOR_EACH_ALLOCNO (a, ai)
- {
- int old_regno = ALLOCNO_REGNO (a);
- int new_regno = REGNO (ALLOCNO_EMIT_DATA (a)->reg);
-
- ALLOCNO_REGNO (a) = new_regno;
-
- if (old_regno != new_regno)
- setup_reg_classes (new_regno, reg_preferred_class (old_regno),
- reg_alternate_class (old_regno),
- reg_allocno_class (old_regno));
- }
- }
- else
- {
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- fprintf (ira_dump_file, "Flattening IR\n");
- ira_flattening (max_regno_before_ira, ira_max_point_before_emit);
- }
- /* New insns were generated: add notes and recalculate live
- info. */
- df_analyze ();
-
- /* ??? Rebuild the loop tree, but why? Does the loop tree
- change if new insns were generated? Can that be handled
- by updating the loop tree incrementally? */
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS
- | LOOPS_HAVE_RECORDED_EXITS);
-
- if (! ira_use_lra_p)
- {
- setup_allocno_assignment_flags ();
- ira_initiate_assign ();
- ira_reassign_conflict_allocnos (max_regno);
- }
- }
- }
-
- ira_finish_emit_data ();
-
- setup_reg_renumber ();
-
- calculate_allocation_cost ();
-
-#ifdef ENABLE_IRA_CHECKING
- if (ira_conflicts_p && ! ira_use_lra_p)
- /* Opposite to reload pass, LRA does not use any conflict info
- from IRA. We don't rebuild conflict info for LRA (through
- ira_flattening call) and cannot use the check here. We could
- rebuild this info for LRA in the check mode but there is a risk
- that code generated with the check and without it will be a bit
- different. Calling ira_flattening in any mode would be a
- wasting CPU time. So do not check the allocation for LRA. */
- check_allocation ();
-#endif
-
- if (max_regno != max_regno_before_ira)
- regstat_recompute_for_max_regno ();
-
- overall_cost_before = ira_overall_cost;
- if (! ira_conflicts_p)
- grow_reg_equivs ();
- else
- {
- fix_reg_equiv_init ();
-
-#ifdef ENABLE_IRA_CHECKING
- print_redundant_copies ();
-#endif
- if (! ira_use_lra_p)
- {
- ira_spilled_reg_stack_slots_num = 0;
- ira_spilled_reg_stack_slots
- = ((class ira_spilled_reg_stack_slot *)
- ira_allocate (max_regno
- * sizeof (class ira_spilled_reg_stack_slot)));
- memset ((void *)ira_spilled_reg_stack_slots, 0,
- max_regno * sizeof (class ira_spilled_reg_stack_slot));
- }
- }
- allocate_initial_values ();
-
- /* See comment for find_moveable_pseudos call. */
- if (ira_conflicts_p)
- move_unallocated_pseudos ();
-
- /* Restore original values. */
- if (lra_simple_p)
- {
- flag_caller_saves = saved_flag_caller_saves;
- flag_ira_region = saved_flag_ira_region;
- }
-}
-
-/* Modify asm goto to avoid further trouble with this insn. We can
- not replace the insn by USE as in other asm insns as we still
- need to keep CFG consistency. */
-void
-ira_nullify_asm_goto (rtx_insn *insn)
-{
- ira_assert (JUMP_P (insn) && INSN_CODE (insn) < 0);
- rtx tmp = extract_asm_operands (PATTERN (insn));
- PATTERN (insn) = gen_rtx_ASM_OPERANDS (VOIDmode, ggc_strdup (""), "", 0,
- rtvec_alloc (0),
- rtvec_alloc (0),
- ASM_OPERANDS_LABEL_VEC (tmp),
- ASM_OPERANDS_SOURCE_LOCATION(tmp));
-}
-
-static void
-do_reload (void)
-{
- basic_block bb;
- bool need_dce;
- unsigned pic_offset_table_regno = INVALID_REGNUM;
-
- if (flag_ira_verbose < 10)
- ira_dump_file = dump_file;
-
- /* If pic_offset_table_rtx is a pseudo register, then keep it so
- after reload to avoid possible wrong usages of hard reg assigned
- to it. */
- if (pic_offset_table_rtx
- && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
- pic_offset_table_regno = REGNO (pic_offset_table_rtx);
-
- timevar_push (TV_RELOAD);
- if (ira_use_lra_p)
- {
- if (current_loops != NULL)
- {
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- }
- FOR_ALL_BB_FN (bb, cfun)
- bb->loop_father = NULL;
- current_loops = NULL;
-
- ira_destroy ();
-
- lra (ira_dump_file);
- /* ???!!! Move it before lra () when we use ira_reg_equiv in
- LRA. */
- vec_free (reg_equivs);
- reg_equivs = NULL;
- need_dce = false;
- }
- else
- {
- df_set_flags (DF_NO_INSN_RESCAN);
- build_insn_chain ();
-
- need_dce = reload (get_insns (), ira_conflicts_p);
- }
-
- timevar_pop (TV_RELOAD);
-
- timevar_push (TV_IRA);
-
- if (ira_conflicts_p && ! ira_use_lra_p)
- {
- ira_free (ira_spilled_reg_stack_slots);
- ira_finish_assign ();
- }
-
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL
- && overall_cost_before != ira_overall_cost)
- fprintf (ira_dump_file, "+++Overall after reload %" PRId64 "\n",
- ira_overall_cost);
-
- flag_ira_share_spill_slots = saved_flag_ira_share_spill_slots;
-
- if (! ira_use_lra_p)
- {
- ira_destroy ();
- if (current_loops != NULL)
- {
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- }
- FOR_ALL_BB_FN (bb, cfun)
- bb->loop_father = NULL;
- current_loops = NULL;
-
- regstat_free_ri ();
- regstat_free_n_sets_and_refs ();
- }
-
- if (optimize)
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- finish_reg_equiv ();
-
- bitmap_obstack_release (&ira_bitmap_obstack);
-#ifndef IRA_NO_OBSTACK
- obstack_free (&ira_obstack, NULL);
-#endif
-
- /* The code after the reload has changed so much that at this point
- we might as well just rescan everything. Note that
- df_rescan_all_insns is not going to help here because it does not
- touch the artificial uses and defs. */
- df_finish_pass (true);
- df_scan_alloc (NULL);
- df_scan_blocks ();
-
- if (optimize > 1)
- {
- df_live_add_problem ();
- df_live_set_all_dirty ();
- }
-
- if (optimize)
- df_analyze ();
-
- if (need_dce && optimize)
- run_fast_dce ();
-
- /* Diagnose uses of the hard frame pointer when it is used as a global
- register. Often we can get away with letting the user appropriate
- the frame pointer, but we should let them know when code generation
- makes that impossible. */
- if (global_regs[HARD_FRAME_POINTER_REGNUM] && frame_pointer_needed)
- {
- tree decl = global_regs_decl[HARD_FRAME_POINTER_REGNUM];
- error_at (DECL_SOURCE_LOCATION (current_function_decl),
- "frame pointer required, but reserved");
- inform (DECL_SOURCE_LOCATION (decl), "for %qD", decl);
- }
-
- /* If we are doing generic stack checking, give a warning if this
- function's frame size is larger than we expect. */
- if (flag_stack_check == GENERIC_STACK_CHECK)
- {
- poly_int64 size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE;
-
- for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (df_regs_ever_live_p (i)
- && !fixed_regs[i]
- && !crtl->abi->clobbers_full_reg_p (i))
- size += UNITS_PER_WORD;
-
- if (constant_lower_bound (size) > STACK_CHECK_MAX_FRAME_SIZE)
- warning (0, "frame size too large for reliable stack checking");
- }
-
- if (pic_offset_table_regno != INVALID_REGNUM)
- pic_offset_table_rtx = gen_rtx_REG (Pmode, pic_offset_table_regno);
-
- timevar_pop (TV_IRA);
-}
-
-/* Run the integrated register allocator. */
-
-namespace {
-
-const pass_data pass_data_ira =
-{
- RTL_PASS, /* type */
- "ira", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_IRA, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_do_not_ggc_collect, /* todo_flags_finish */
-};
-
-class pass_ira : public rtl_opt_pass
-{
-public:
- pass_ira (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_ira, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return !targetm.no_register_allocation;
- }
- virtual unsigned int execute (function *)
- {
- ira (dump_file);
- return 0;
- }
-
-}; // class pass_ira
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_ira (gcc::context *ctxt)
-{
- return new pass_ira (ctxt);
-}
-
-namespace {
-
-const pass_data pass_data_reload =
-{
- RTL_PASS, /* type */
- "reload", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_RELOAD, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_reload : public rtl_opt_pass
-{
-public:
- pass_reload (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_reload, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return !targetm.no_register_allocation;
- }
- virtual unsigned int execute (function *)
- {
- do_reload ();
- return 0;
- }
-
-}; // class pass_reload
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_reload (gcc::context *ctxt)
-{
- return new pass_reload (ctxt);
-}