diff options
author | Martin Liska <mliska@suse.cz> | 2022-01-14 16:56:44 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-01-17 22:12:04 +0100 |
commit | 5c69acb32329d49e58c26fa41ae74229a52b9106 (patch) | |
tree | ddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/ifcvt.c | |
parent | 490e23032baaece71f2ec09fa1805064b150fbc2 (diff) | |
download | gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2 |
Rename .c files to .cc files.
gcc/ada/ChangeLog:
* adadecode.c: Moved to...
* adadecode.cc: ...here.
* affinity.c: Moved to...
* affinity.cc: ...here.
* argv-lynxos178-raven-cert.c: Moved to...
* argv-lynxos178-raven-cert.cc: ...here.
* argv.c: Moved to...
* argv.cc: ...here.
* aux-io.c: Moved to...
* aux-io.cc: ...here.
* cio.c: Moved to...
* cio.cc: ...here.
* cstreams.c: Moved to...
* cstreams.cc: ...here.
* env.c: Moved to...
* env.cc: ...here.
* exit.c: Moved to...
* exit.cc: ...here.
* expect.c: Moved to...
* expect.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* gcc-interface/cuintp.c: Moved to...
* gcc-interface/cuintp.cc: ...here.
* gcc-interface/decl.c: Moved to...
* gcc-interface/decl.cc: ...here.
* gcc-interface/misc.c: Moved to...
* gcc-interface/misc.cc: ...here.
* gcc-interface/targtyps.c: Moved to...
* gcc-interface/targtyps.cc: ...here.
* gcc-interface/trans.c: Moved to...
* gcc-interface/trans.cc: ...here.
* gcc-interface/utils.c: Moved to...
* gcc-interface/utils.cc: ...here.
* gcc-interface/utils2.c: Moved to...
* gcc-interface/utils2.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* initialize.c: Moved to...
* initialize.cc: ...here.
* libgnarl/thread.c: Moved to...
* libgnarl/thread.cc: ...here.
* link.c: Moved to...
* link.cc: ...here.
* locales.c: Moved to...
* locales.cc: ...here.
* mkdir.c: Moved to...
* mkdir.cc: ...here.
* raise.c: Moved to...
* raise.cc: ...here.
* rtfinal.c: Moved to...
* rtfinal.cc: ...here.
* rtinit.c: Moved to...
* rtinit.cc: ...here.
* seh_init.c: Moved to...
* seh_init.cc: ...here.
* sigtramp-armdroid.c: Moved to...
* sigtramp-armdroid.cc: ...here.
* sigtramp-ios.c: Moved to...
* sigtramp-ios.cc: ...here.
* sigtramp-qnx.c: Moved to...
* sigtramp-qnx.cc: ...here.
* sigtramp-vxworks.c: Moved to...
* sigtramp-vxworks.cc: ...here.
* socket.c: Moved to...
* socket.cc: ...here.
* tracebak.c: Moved to...
* tracebak.cc: ...here.
* version.c: Moved to...
* version.cc: ...here.
* vx_stack_info.c: Moved to...
* vx_stack_info.cc: ...here.
gcc/ChangeLog:
* adjust-alignment.c: Moved to...
* adjust-alignment.cc: ...here.
* alias.c: Moved to...
* alias.cc: ...here.
* alloc-pool.c: Moved to...
* alloc-pool.cc: ...here.
* asan.c: Moved to...
* asan.cc: ...here.
* attribs.c: Moved to...
* attribs.cc: ...here.
* auto-inc-dec.c: Moved to...
* auto-inc-dec.cc: ...here.
* auto-profile.c: Moved to...
* auto-profile.cc: ...here.
* bb-reorder.c: Moved to...
* bb-reorder.cc: ...here.
* bitmap.c: Moved to...
* bitmap.cc: ...here.
* btfout.c: Moved to...
* btfout.cc: ...here.
* builtins.c: Moved to...
* builtins.cc: ...here.
* caller-save.c: Moved to...
* caller-save.cc: ...here.
* calls.c: Moved to...
* calls.cc: ...here.
* ccmp.c: Moved to...
* ccmp.cc: ...here.
* cfg.c: Moved to...
* cfg.cc: ...here.
* cfganal.c: Moved to...
* cfganal.cc: ...here.
* cfgbuild.c: Moved to...
* cfgbuild.cc: ...here.
* cfgcleanup.c: Moved to...
* cfgcleanup.cc: ...here.
* cfgexpand.c: Moved to...
* cfgexpand.cc: ...here.
* cfghooks.c: Moved to...
* cfghooks.cc: ...here.
* cfgloop.c: Moved to...
* cfgloop.cc: ...here.
* cfgloopanal.c: Moved to...
* cfgloopanal.cc: ...here.
* cfgloopmanip.c: Moved to...
* cfgloopmanip.cc: ...here.
* cfgrtl.c: Moved to...
* cfgrtl.cc: ...here.
* cgraph.c: Moved to...
* cgraph.cc: ...here.
* cgraphbuild.c: Moved to...
* cgraphbuild.cc: ...here.
* cgraphclones.c: Moved to...
* cgraphclones.cc: ...here.
* cgraphunit.c: Moved to...
* cgraphunit.cc: ...here.
* collect-utils.c: Moved to...
* collect-utils.cc: ...here.
* collect2-aix.c: Moved to...
* collect2-aix.cc: ...here.
* collect2.c: Moved to...
* collect2.cc: ...here.
* combine-stack-adj.c: Moved to...
* combine-stack-adj.cc: ...here.
* combine.c: Moved to...
* combine.cc: ...here.
* common/common-targhooks.c: Moved to...
* common/common-targhooks.cc: ...here.
* common/config/aarch64/aarch64-common.c: Moved to...
* common/config/aarch64/aarch64-common.cc: ...here.
* common/config/alpha/alpha-common.c: Moved to...
* common/config/alpha/alpha-common.cc: ...here.
* common/config/arc/arc-common.c: Moved to...
* common/config/arc/arc-common.cc: ...here.
* common/config/arm/arm-common.c: Moved to...
* common/config/arm/arm-common.cc: ...here.
* common/config/avr/avr-common.c: Moved to...
* common/config/avr/avr-common.cc: ...here.
* common/config/bfin/bfin-common.c: Moved to...
* common/config/bfin/bfin-common.cc: ...here.
* common/config/bpf/bpf-common.c: Moved to...
* common/config/bpf/bpf-common.cc: ...here.
* common/config/c6x/c6x-common.c: Moved to...
* common/config/c6x/c6x-common.cc: ...here.
* common/config/cr16/cr16-common.c: Moved to...
* common/config/cr16/cr16-common.cc: ...here.
* common/config/cris/cris-common.c: Moved to...
* common/config/cris/cris-common.cc: ...here.
* common/config/csky/csky-common.c: Moved to...
* common/config/csky/csky-common.cc: ...here.
* common/config/default-common.c: Moved to...
* common/config/default-common.cc: ...here.
* common/config/epiphany/epiphany-common.c: Moved to...
* common/config/epiphany/epiphany-common.cc: ...here.
* common/config/fr30/fr30-common.c: Moved to...
* common/config/fr30/fr30-common.cc: ...here.
* common/config/frv/frv-common.c: Moved to...
* common/config/frv/frv-common.cc: ...here.
* common/config/gcn/gcn-common.c: Moved to...
* common/config/gcn/gcn-common.cc: ...here.
* common/config/h8300/h8300-common.c: Moved to...
* common/config/h8300/h8300-common.cc: ...here.
* common/config/i386/i386-common.c: Moved to...
* common/config/i386/i386-common.cc: ...here.
* common/config/ia64/ia64-common.c: Moved to...
* common/config/ia64/ia64-common.cc: ...here.
* common/config/iq2000/iq2000-common.c: Moved to...
* common/config/iq2000/iq2000-common.cc: ...here.
* common/config/lm32/lm32-common.c: Moved to...
* common/config/lm32/lm32-common.cc: ...here.
* common/config/m32r/m32r-common.c: Moved to...
* common/config/m32r/m32r-common.cc: ...here.
* common/config/m68k/m68k-common.c: Moved to...
* common/config/m68k/m68k-common.cc: ...here.
* common/config/mcore/mcore-common.c: Moved to...
* common/config/mcore/mcore-common.cc: ...here.
* common/config/microblaze/microblaze-common.c: Moved to...
* common/config/microblaze/microblaze-common.cc: ...here.
* common/config/mips/mips-common.c: Moved to...
* common/config/mips/mips-common.cc: ...here.
* common/config/mmix/mmix-common.c: Moved to...
* common/config/mmix/mmix-common.cc: ...here.
* common/config/mn10300/mn10300-common.c: Moved to...
* common/config/mn10300/mn10300-common.cc: ...here.
* common/config/msp430/msp430-common.c: Moved to...
* common/config/msp430/msp430-common.cc: ...here.
* common/config/nds32/nds32-common.c: Moved to...
* common/config/nds32/nds32-common.cc: ...here.
* common/config/nios2/nios2-common.c: Moved to...
* common/config/nios2/nios2-common.cc: ...here.
* common/config/nvptx/nvptx-common.c: Moved to...
* common/config/nvptx/nvptx-common.cc: ...here.
* common/config/or1k/or1k-common.c: Moved to...
* common/config/or1k/or1k-common.cc: ...here.
* common/config/pa/pa-common.c: Moved to...
* common/config/pa/pa-common.cc: ...here.
* common/config/pdp11/pdp11-common.c: Moved to...
* common/config/pdp11/pdp11-common.cc: ...here.
* common/config/pru/pru-common.c: Moved to...
* common/config/pru/pru-common.cc: ...here.
* common/config/riscv/riscv-common.c: Moved to...
* common/config/riscv/riscv-common.cc: ...here.
* common/config/rs6000/rs6000-common.c: Moved to...
* common/config/rs6000/rs6000-common.cc: ...here.
* common/config/rx/rx-common.c: Moved to...
* common/config/rx/rx-common.cc: ...here.
* common/config/s390/s390-common.c: Moved to...
* common/config/s390/s390-common.cc: ...here.
* common/config/sh/sh-common.c: Moved to...
* common/config/sh/sh-common.cc: ...here.
* common/config/sparc/sparc-common.c: Moved to...
* common/config/sparc/sparc-common.cc: ...here.
* common/config/tilegx/tilegx-common.c: Moved to...
* common/config/tilegx/tilegx-common.cc: ...here.
* common/config/tilepro/tilepro-common.c: Moved to...
* common/config/tilepro/tilepro-common.cc: ...here.
* common/config/v850/v850-common.c: Moved to...
* common/config/v850/v850-common.cc: ...here.
* common/config/vax/vax-common.c: Moved to...
* common/config/vax/vax-common.cc: ...here.
* common/config/visium/visium-common.c: Moved to...
* common/config/visium/visium-common.cc: ...here.
* common/config/xstormy16/xstormy16-common.c: Moved to...
* common/config/xstormy16/xstormy16-common.cc: ...here.
* common/config/xtensa/xtensa-common.c: Moved to...
* common/config/xtensa/xtensa-common.cc: ...here.
* compare-elim.c: Moved to...
* compare-elim.cc: ...here.
* config/aarch64/aarch64-bti-insert.c: Moved to...
* config/aarch64/aarch64-bti-insert.cc: ...here.
* config/aarch64/aarch64-builtins.c: Moved to...
* config/aarch64/aarch64-builtins.cc: ...here.
* config/aarch64/aarch64-c.c: Moved to...
* config/aarch64/aarch64-c.cc: ...here.
* config/aarch64/aarch64-d.c: Moved to...
* config/aarch64/aarch64-d.cc: ...here.
* config/aarch64/aarch64.c: Moved to...
* config/aarch64/aarch64.cc: ...here.
* config/aarch64/cortex-a57-fma-steering.c: Moved to...
* config/aarch64/cortex-a57-fma-steering.cc: ...here.
* config/aarch64/driver-aarch64.c: Moved to...
* config/aarch64/driver-aarch64.cc: ...here.
* config/aarch64/falkor-tag-collision-avoidance.c: Moved to...
* config/aarch64/falkor-tag-collision-avoidance.cc: ...here.
* config/aarch64/host-aarch64-darwin.c: Moved to...
* config/aarch64/host-aarch64-darwin.cc: ...here.
* config/alpha/alpha.c: Moved to...
* config/alpha/alpha.cc: ...here.
* config/alpha/driver-alpha.c: Moved to...
* config/alpha/driver-alpha.cc: ...here.
* config/arc/arc-c.c: Moved to...
* config/arc/arc-c.cc: ...here.
* config/arc/arc.c: Moved to...
* config/arc/arc.cc: ...here.
* config/arc/driver-arc.c: Moved to...
* config/arc/driver-arc.cc: ...here.
* config/arm/aarch-common.c: Moved to...
* config/arm/aarch-common.cc: ...here.
* config/arm/arm-builtins.c: Moved to...
* config/arm/arm-builtins.cc: ...here.
* config/arm/arm-c.c: Moved to...
* config/arm/arm-c.cc: ...here.
* config/arm/arm-d.c: Moved to...
* config/arm/arm-d.cc: ...here.
* config/arm/arm.c: Moved to...
* config/arm/arm.cc: ...here.
* config/arm/driver-arm.c: Moved to...
* config/arm/driver-arm.cc: ...here.
* config/avr/avr-c.c: Moved to...
* config/avr/avr-c.cc: ...here.
* config/avr/avr-devices.c: Moved to...
* config/avr/avr-devices.cc: ...here.
* config/avr/avr-log.c: Moved to...
* config/avr/avr-log.cc: ...here.
* config/avr/avr.c: Moved to...
* config/avr/avr.cc: ...here.
* config/avr/driver-avr.c: Moved to...
* config/avr/driver-avr.cc: ...here.
* config/avr/gen-avr-mmcu-specs.c: Moved to...
* config/avr/gen-avr-mmcu-specs.cc: ...here.
* config/avr/gen-avr-mmcu-texi.c: Moved to...
* config/avr/gen-avr-mmcu-texi.cc: ...here.
* config/bfin/bfin.c: Moved to...
* config/bfin/bfin.cc: ...here.
* config/bpf/bpf.c: Moved to...
* config/bpf/bpf.cc: ...here.
* config/bpf/coreout.c: Moved to...
* config/bpf/coreout.cc: ...here.
* config/c6x/c6x.c: Moved to...
* config/c6x/c6x.cc: ...here.
* config/cr16/cr16.c: Moved to...
* config/cr16/cr16.cc: ...here.
* config/cris/cris.c: Moved to...
* config/cris/cris.cc: ...here.
* config/csky/csky.c: Moved to...
* config/csky/csky.cc: ...here.
* config/darwin-c.c: Moved to...
* config/darwin-c.cc: ...here.
* config/darwin-d.c: Moved to...
* config/darwin-d.cc: ...here.
* config/darwin-driver.c: Moved to...
* config/darwin-driver.cc: ...here.
* config/darwin-f.c: Moved to...
* config/darwin-f.cc: ...here.
* config/darwin.c: Moved to...
* config/darwin.cc: ...here.
* config/default-c.c: Moved to...
* config/default-c.cc: ...here.
* config/default-d.c: Moved to...
* config/default-d.cc: ...here.
* config/dragonfly-d.c: Moved to...
* config/dragonfly-d.cc: ...here.
* config/epiphany/epiphany.c: Moved to...
* config/epiphany/epiphany.cc: ...here.
* config/epiphany/mode-switch-use.c: Moved to...
* config/epiphany/mode-switch-use.cc: ...here.
* config/epiphany/resolve-sw-modes.c: Moved to...
* config/epiphany/resolve-sw-modes.cc: ...here.
* config/fr30/fr30.c: Moved to...
* config/fr30/fr30.cc: ...here.
* config/freebsd-d.c: Moved to...
* config/freebsd-d.cc: ...here.
* config/frv/frv.c: Moved to...
* config/frv/frv.cc: ...here.
* config/ft32/ft32.c: Moved to...
* config/ft32/ft32.cc: ...here.
* config/gcn/driver-gcn.c: Moved to...
* config/gcn/driver-gcn.cc: ...here.
* config/gcn/gcn-run.c: Moved to...
* config/gcn/gcn-run.cc: ...here.
* config/gcn/gcn-tree.c: Moved to...
* config/gcn/gcn-tree.cc: ...here.
* config/gcn/gcn.c: Moved to...
* config/gcn/gcn.cc: ...here.
* config/gcn/mkoffload.c: Moved to...
* config/gcn/mkoffload.cc: ...here.
* config/glibc-c.c: Moved to...
* config/glibc-c.cc: ...here.
* config/glibc-d.c: Moved to...
* config/glibc-d.cc: ...here.
* config/h8300/h8300.c: Moved to...
* config/h8300/h8300.cc: ...here.
* config/host-darwin.c: Moved to...
* config/host-darwin.cc: ...here.
* config/host-hpux.c: Moved to...
* config/host-hpux.cc: ...here.
* config/host-linux.c: Moved to...
* config/host-linux.cc: ...here.
* config/host-netbsd.c: Moved to...
* config/host-netbsd.cc: ...here.
* config/host-openbsd.c: Moved to...
* config/host-openbsd.cc: ...here.
* config/host-solaris.c: Moved to...
* config/host-solaris.cc: ...here.
* config/i386/djgpp.c: Moved to...
* config/i386/djgpp.cc: ...here.
* config/i386/driver-i386.c: Moved to...
* config/i386/driver-i386.cc: ...here.
* config/i386/driver-mingw32.c: Moved to...
* config/i386/driver-mingw32.cc: ...here.
* config/i386/gnu-property.c: Moved to...
* config/i386/gnu-property.cc: ...here.
* config/i386/host-cygwin.c: Moved to...
* config/i386/host-cygwin.cc: ...here.
* config/i386/host-i386-darwin.c: Moved to...
* config/i386/host-i386-darwin.cc: ...here.
* config/i386/host-mingw32.c: Moved to...
* config/i386/host-mingw32.cc: ...here.
* config/i386/i386-builtins.c: Moved to...
* config/i386/i386-builtins.cc: ...here.
* config/i386/i386-c.c: Moved to...
* config/i386/i386-c.cc: ...here.
* config/i386/i386-d.c: Moved to...
* config/i386/i386-d.cc: ...here.
* config/i386/i386-expand.c: Moved to...
* config/i386/i386-expand.cc: ...here.
* config/i386/i386-features.c: Moved to...
* config/i386/i386-features.cc: ...here.
* config/i386/i386-options.c: Moved to...
* config/i386/i386-options.cc: ...here.
* config/i386/i386.c: Moved to...
* config/i386/i386.cc: ...here.
* config/i386/intelmic-mkoffload.c: Moved to...
* config/i386/intelmic-mkoffload.cc: ...here.
* config/i386/msformat-c.c: Moved to...
* config/i386/msformat-c.cc: ...here.
* config/i386/winnt-cxx.c: Moved to...
* config/i386/winnt-cxx.cc: ...here.
* config/i386/winnt-d.c: Moved to...
* config/i386/winnt-d.cc: ...here.
* config/i386/winnt-stubs.c: Moved to...
* config/i386/winnt-stubs.cc: ...here.
* config/i386/winnt.c: Moved to...
* config/i386/winnt.cc: ...here.
* config/i386/x86-tune-sched-atom.c: Moved to...
* config/i386/x86-tune-sched-atom.cc: ...here.
* config/i386/x86-tune-sched-bd.c: Moved to...
* config/i386/x86-tune-sched-bd.cc: ...here.
* config/i386/x86-tune-sched-core.c: Moved to...
* config/i386/x86-tune-sched-core.cc: ...here.
* config/i386/x86-tune-sched.c: Moved to...
* config/i386/x86-tune-sched.cc: ...here.
* config/ia64/ia64-c.c: Moved to...
* config/ia64/ia64-c.cc: ...here.
* config/ia64/ia64.c: Moved to...
* config/ia64/ia64.cc: ...here.
* config/iq2000/iq2000.c: Moved to...
* config/iq2000/iq2000.cc: ...here.
* config/linux.c: Moved to...
* config/linux.cc: ...here.
* config/lm32/lm32.c: Moved to...
* config/lm32/lm32.cc: ...here.
* config/m32c/m32c-pragma.c: Moved to...
* config/m32c/m32c-pragma.cc: ...here.
* config/m32c/m32c.c: Moved to...
* config/m32c/m32c.cc: ...here.
* config/m32r/m32r.c: Moved to...
* config/m32r/m32r.cc: ...here.
* config/m68k/m68k.c: Moved to...
* config/m68k/m68k.cc: ...here.
* config/mcore/mcore.c: Moved to...
* config/mcore/mcore.cc: ...here.
* config/microblaze/microblaze-c.c: Moved to...
* config/microblaze/microblaze-c.cc: ...here.
* config/microblaze/microblaze.c: Moved to...
* config/microblaze/microblaze.cc: ...here.
* config/mips/driver-native.c: Moved to...
* config/mips/driver-native.cc: ...here.
* config/mips/frame-header-opt.c: Moved to...
* config/mips/frame-header-opt.cc: ...here.
* config/mips/mips-d.c: Moved to...
* config/mips/mips-d.cc: ...here.
* config/mips/mips.c: Moved to...
* config/mips/mips.cc: ...here.
* config/mmix/mmix.c: Moved to...
* config/mmix/mmix.cc: ...here.
* config/mn10300/mn10300.c: Moved to...
* config/mn10300/mn10300.cc: ...here.
* config/moxie/moxie.c: Moved to...
* config/moxie/moxie.cc: ...here.
* config/msp430/driver-msp430.c: Moved to...
* config/msp430/driver-msp430.cc: ...here.
* config/msp430/msp430-c.c: Moved to...
* config/msp430/msp430-c.cc: ...here.
* config/msp430/msp430-devices.c: Moved to...
* config/msp430/msp430-devices.cc: ...here.
* config/msp430/msp430.c: Moved to...
* config/msp430/msp430.cc: ...here.
* config/nds32/nds32-cost.c: Moved to...
* config/nds32/nds32-cost.cc: ...here.
* config/nds32/nds32-fp-as-gp.c: Moved to...
* config/nds32/nds32-fp-as-gp.cc: ...here.
* config/nds32/nds32-intrinsic.c: Moved to...
* config/nds32/nds32-intrinsic.cc: ...here.
* config/nds32/nds32-isr.c: Moved to...
* config/nds32/nds32-isr.cc: ...here.
* config/nds32/nds32-md-auxiliary.c: Moved to...
* config/nds32/nds32-md-auxiliary.cc: ...here.
* config/nds32/nds32-memory-manipulation.c: Moved to...
* config/nds32/nds32-memory-manipulation.cc: ...here.
* config/nds32/nds32-pipelines-auxiliary.c: Moved to...
* config/nds32/nds32-pipelines-auxiliary.cc: ...here.
* config/nds32/nds32-predicates.c: Moved to...
* config/nds32/nds32-predicates.cc: ...here.
* config/nds32/nds32-relax-opt.c: Moved to...
* config/nds32/nds32-relax-opt.cc: ...here.
* config/nds32/nds32-utils.c: Moved to...
* config/nds32/nds32-utils.cc: ...here.
* config/nds32/nds32.c: Moved to...
* config/nds32/nds32.cc: ...here.
* config/netbsd-d.c: Moved to...
* config/netbsd-d.cc: ...here.
* config/netbsd.c: Moved to...
* config/netbsd.cc: ...here.
* config/nios2/nios2.c: Moved to...
* config/nios2/nios2.cc: ...here.
* config/nvptx/mkoffload.c: Moved to...
* config/nvptx/mkoffload.cc: ...here.
* config/nvptx/nvptx-c.c: Moved to...
* config/nvptx/nvptx-c.cc: ...here.
* config/nvptx/nvptx.c: Moved to...
* config/nvptx/nvptx.cc: ...here.
* config/openbsd-d.c: Moved to...
* config/openbsd-d.cc: ...here.
* config/or1k/or1k.c: Moved to...
* config/or1k/or1k.cc: ...here.
* config/pa/pa-d.c: Moved to...
* config/pa/pa-d.cc: ...here.
* config/pa/pa.c: Moved to...
* config/pa/pa.cc: ...here.
* config/pdp11/pdp11.c: Moved to...
* config/pdp11/pdp11.cc: ...here.
* config/pru/pru-passes.c: Moved to...
* config/pru/pru-passes.cc: ...here.
* config/pru/pru-pragma.c: Moved to...
* config/pru/pru-pragma.cc: ...here.
* config/pru/pru.c: Moved to...
* config/pru/pru.cc: ...here.
* config/riscv/riscv-builtins.c: Moved to...
* config/riscv/riscv-builtins.cc: ...here.
* config/riscv/riscv-c.c: Moved to...
* config/riscv/riscv-c.cc: ...here.
* config/riscv/riscv-d.c: Moved to...
* config/riscv/riscv-d.cc: ...here.
* config/riscv/riscv-shorten-memrefs.c: Moved to...
* config/riscv/riscv-shorten-memrefs.cc: ...here.
* config/riscv/riscv-sr.c: Moved to...
* config/riscv/riscv-sr.cc: ...here.
* config/riscv/riscv.c: Moved to...
* config/riscv/riscv.cc: ...here.
* config/rl78/rl78-c.c: Moved to...
* config/rl78/rl78-c.cc: ...here.
* config/rl78/rl78.c: Moved to...
* config/rl78/rl78.cc: ...here.
* config/rs6000/driver-rs6000.c: Moved to...
* config/rs6000/driver-rs6000.cc: ...here.
* config/rs6000/host-darwin.c: Moved to...
* config/rs6000/host-darwin.cc: ...here.
* config/rs6000/host-ppc64-darwin.c: Moved to...
* config/rs6000/host-ppc64-darwin.cc: ...here.
* config/rs6000/rbtree.c: Moved to...
* config/rs6000/rbtree.cc: ...here.
* config/rs6000/rs6000-c.c: Moved to...
* config/rs6000/rs6000-c.cc: ...here.
* config/rs6000/rs6000-call.c: Moved to...
* config/rs6000/rs6000-call.cc: ...here.
* config/rs6000/rs6000-d.c: Moved to...
* config/rs6000/rs6000-d.cc: ...here.
* config/rs6000/rs6000-gen-builtins.c: Moved to...
* config/rs6000/rs6000-gen-builtins.cc: ...here.
* config/rs6000/rs6000-linux.c: Moved to...
* config/rs6000/rs6000-linux.cc: ...here.
* config/rs6000/rs6000-logue.c: Moved to...
* config/rs6000/rs6000-logue.cc: ...here.
* config/rs6000/rs6000-p8swap.c: Moved to...
* config/rs6000/rs6000-p8swap.cc: ...here.
* config/rs6000/rs6000-pcrel-opt.c: Moved to...
* config/rs6000/rs6000-pcrel-opt.cc: ...here.
* config/rs6000/rs6000-string.c: Moved to...
* config/rs6000/rs6000-string.cc: ...here.
* config/rs6000/rs6000.c: Moved to...
* config/rs6000/rs6000.cc: ...here.
* config/rx/rx.c: Moved to...
* config/rx/rx.cc: ...here.
* config/s390/driver-native.c: Moved to...
* config/s390/driver-native.cc: ...here.
* config/s390/s390-c.c: Moved to...
* config/s390/s390-c.cc: ...here.
* config/s390/s390-d.c: Moved to...
* config/s390/s390-d.cc: ...here.
* config/s390/s390.c: Moved to...
* config/s390/s390.cc: ...here.
* config/sh/divtab-sh4-300.c: Moved to...
* config/sh/divtab-sh4-300.cc: ...here.
* config/sh/divtab-sh4.c: Moved to...
* config/sh/divtab-sh4.cc: ...here.
* config/sh/divtab.c: Moved to...
* config/sh/divtab.cc: ...here.
* config/sh/sh-c.c: Moved to...
* config/sh/sh-c.cc: ...here.
* config/sh/sh.c: Moved to...
* config/sh/sh.cc: ...here.
* config/sol2-c.c: Moved to...
* config/sol2-c.cc: ...here.
* config/sol2-cxx.c: Moved to...
* config/sol2-cxx.cc: ...here.
* config/sol2-d.c: Moved to...
* config/sol2-d.cc: ...here.
* config/sol2-stubs.c: Moved to...
* config/sol2-stubs.cc: ...here.
* config/sol2.c: Moved to...
* config/sol2.cc: ...here.
* config/sparc/driver-sparc.c: Moved to...
* config/sparc/driver-sparc.cc: ...here.
* config/sparc/sparc-c.c: Moved to...
* config/sparc/sparc-c.cc: ...here.
* config/sparc/sparc-d.c: Moved to...
* config/sparc/sparc-d.cc: ...here.
* config/sparc/sparc.c: Moved to...
* config/sparc/sparc.cc: ...here.
* config/stormy16/stormy16.c: Moved to...
* config/stormy16/stormy16.cc: ...here.
* config/tilegx/mul-tables.c: Moved to...
* config/tilegx/mul-tables.cc: ...here.
* config/tilegx/tilegx-c.c: Moved to...
* config/tilegx/tilegx-c.cc: ...here.
* config/tilegx/tilegx.c: Moved to...
* config/tilegx/tilegx.cc: ...here.
* config/tilepro/mul-tables.c: Moved to...
* config/tilepro/mul-tables.cc: ...here.
* config/tilepro/tilepro-c.c: Moved to...
* config/tilepro/tilepro-c.cc: ...here.
* config/tilepro/tilepro.c: Moved to...
* config/tilepro/tilepro.cc: ...here.
* config/v850/v850-c.c: Moved to...
* config/v850/v850-c.cc: ...here.
* config/v850/v850.c: Moved to...
* config/v850/v850.cc: ...here.
* config/vax/vax.c: Moved to...
* config/vax/vax.cc: ...here.
* config/visium/visium.c: Moved to...
* config/visium/visium.cc: ...here.
* config/vms/vms-c.c: Moved to...
* config/vms/vms-c.cc: ...here.
* config/vms/vms-f.c: Moved to...
* config/vms/vms-f.cc: ...here.
* config/vms/vms.c: Moved to...
* config/vms/vms.cc: ...here.
* config/vxworks-c.c: Moved to...
* config/vxworks-c.cc: ...here.
* config/vxworks.c: Moved to...
* config/vxworks.cc: ...here.
* config/winnt-c.c: Moved to...
* config/winnt-c.cc: ...here.
* config/xtensa/xtensa.c: Moved to...
* config/xtensa/xtensa.cc: ...here.
* context.c: Moved to...
* context.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* coverage.c: Moved to...
* coverage.cc: ...here.
* cppbuiltin.c: Moved to...
* cppbuiltin.cc: ...here.
* cppdefault.c: Moved to...
* cppdefault.cc: ...here.
* cprop.c: Moved to...
* cprop.cc: ...here.
* cse.c: Moved to...
* cse.cc: ...here.
* cselib.c: Moved to...
* cselib.cc: ...here.
* ctfc.c: Moved to...
* ctfc.cc: ...here.
* ctfout.c: Moved to...
* ctfout.cc: ...here.
* data-streamer-in.c: Moved to...
* data-streamer-in.cc: ...here.
* data-streamer-out.c: Moved to...
* data-streamer-out.cc: ...here.
* data-streamer.c: Moved to...
* data-streamer.cc: ...here.
* dbgcnt.c: Moved to...
* dbgcnt.cc: ...here.
* dbxout.c: Moved to...
* dbxout.cc: ...here.
* dce.c: Moved to...
* dce.cc: ...here.
* ddg.c: Moved to...
* ddg.cc: ...here.
* debug.c: Moved to...
* debug.cc: ...here.
* df-core.c: Moved to...
* df-core.cc: ...here.
* df-problems.c: Moved to...
* df-problems.cc: ...here.
* df-scan.c: Moved to...
* df-scan.cc: ...here.
* dfp.c: Moved to...
* dfp.cc: ...here.
* diagnostic-color.c: Moved to...
* diagnostic-color.cc: ...here.
* diagnostic-show-locus.c: Moved to...
* diagnostic-show-locus.cc: ...here.
* diagnostic-spec.c: Moved to...
* diagnostic-spec.cc: ...here.
* diagnostic.c: Moved to...
* diagnostic.cc: ...here.
* dojump.c: Moved to...
* dojump.cc: ...here.
* dominance.c: Moved to...
* dominance.cc: ...here.
* domwalk.c: Moved to...
* domwalk.cc: ...here.
* double-int.c: Moved to...
* double-int.cc: ...here.
* dse.c: Moved to...
* dse.cc: ...here.
* dumpfile.c: Moved to...
* dumpfile.cc: ...here.
* dwarf2asm.c: Moved to...
* dwarf2asm.cc: ...here.
* dwarf2cfi.c: Moved to...
* dwarf2cfi.cc: ...here.
* dwarf2ctf.c: Moved to...
* dwarf2ctf.cc: ...here.
* dwarf2out.c: Moved to...
* dwarf2out.cc: ...here.
* early-remat.c: Moved to...
* early-remat.cc: ...here.
* edit-context.c: Moved to...
* edit-context.cc: ...here.
* emit-rtl.c: Moved to...
* emit-rtl.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* et-forest.c: Moved to...
* et-forest.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* explow.c: Moved to...
* explow.cc: ...here.
* expmed.c: Moved to...
* expmed.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* fibonacci_heap.c: Moved to...
* fibonacci_heap.cc: ...here.
* file-find.c: Moved to...
* file-find.cc: ...here.
* file-prefix-map.c: Moved to...
* file-prefix-map.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* fixed-value.c: Moved to...
* fixed-value.cc: ...here.
* fold-const-call.c: Moved to...
* fold-const-call.cc: ...here.
* fold-const.c: Moved to...
* fold-const.cc: ...here.
* fp-test.c: Moved to...
* fp-test.cc: ...here.
* function-tests.c: Moved to...
* function-tests.cc: ...here.
* function.c: Moved to...
* function.cc: ...here.
* fwprop.c: Moved to...
* fwprop.cc: ...here.
* gcc-ar.c: Moved to...
* gcc-ar.cc: ...here.
* gcc-main.c: Moved to...
* gcc-main.cc: ...here.
* gcc-rich-location.c: Moved to...
* gcc-rich-location.cc: ...here.
* gcc.c: Moved to...
* gcc.cc: ...here.
* gcov-dump.c: Moved to...
* gcov-dump.cc: ...here.
* gcov-io.c: Moved to...
* gcov-io.cc: ...here.
* gcov-tool.c: Moved to...
* gcov-tool.cc: ...here.
* gcov.c: Moved to...
* gcov.cc: ...here.
* gcse-common.c: Moved to...
* gcse-common.cc: ...here.
* gcse.c: Moved to...
* gcse.cc: ...here.
* genattr-common.c: Moved to...
* genattr-common.cc: ...here.
* genattr.c: Moved to...
* genattr.cc: ...here.
* genattrtab.c: Moved to...
* genattrtab.cc: ...here.
* genautomata.c: Moved to...
* genautomata.cc: ...here.
* gencfn-macros.c: Moved to...
* gencfn-macros.cc: ...here.
* gencheck.c: Moved to...
* gencheck.cc: ...here.
* genchecksum.c: Moved to...
* genchecksum.cc: ...here.
* gencodes.c: Moved to...
* gencodes.cc: ...here.
* genconditions.c: Moved to...
* genconditions.cc: ...here.
* genconfig.c: Moved to...
* genconfig.cc: ...here.
* genconstants.c: Moved to...
* genconstants.cc: ...here.
* genemit.c: Moved to...
* genemit.cc: ...here.
* genenums.c: Moved to...
* genenums.cc: ...here.
* generic-match-head.c: Moved to...
* generic-match-head.cc: ...here.
* genextract.c: Moved to...
* genextract.cc: ...here.
* genflags.c: Moved to...
* genflags.cc: ...here.
* gengenrtl.c: Moved to...
* gengenrtl.cc: ...here.
* gengtype-parse.c: Moved to...
* gengtype-parse.cc: ...here.
* gengtype-state.c: Moved to...
* gengtype-state.cc: ...here.
* gengtype.c: Moved to...
* gengtype.cc: ...here.
* genhooks.c: Moved to...
* genhooks.cc: ...here.
* genmatch.c: Moved to...
* genmatch.cc: ...here.
* genmddeps.c: Moved to...
* genmddeps.cc: ...here.
* genmddump.c: Moved to...
* genmddump.cc: ...here.
* genmodes.c: Moved to...
* genmodes.cc: ...here.
* genopinit.c: Moved to...
* genopinit.cc: ...here.
* genoutput.c: Moved to...
* genoutput.cc: ...here.
* genpeep.c: Moved to...
* genpeep.cc: ...here.
* genpreds.c: Moved to...
* genpreds.cc: ...here.
* genrecog.c: Moved to...
* genrecog.cc: ...here.
* gensupport.c: Moved to...
* gensupport.cc: ...here.
* gentarget-def.c: Moved to...
* gentarget-def.cc: ...here.
* genversion.c: Moved to...
* genversion.cc: ...here.
* ggc-common.c: Moved to...
* ggc-common.cc: ...here.
* ggc-none.c: Moved to...
* ggc-none.cc: ...here.
* ggc-page.c: Moved to...
* ggc-page.cc: ...here.
* ggc-tests.c: Moved to...
* ggc-tests.cc: ...here.
* gimple-builder.c: Moved to...
* gimple-builder.cc: ...here.
* gimple-expr.c: Moved to...
* gimple-expr.cc: ...here.
* gimple-fold.c: Moved to...
* gimple-fold.cc: ...here.
* gimple-iterator.c: Moved to...
* gimple-iterator.cc: ...here.
* gimple-laddress.c: Moved to...
* gimple-laddress.cc: ...here.
* gimple-loop-jam.c: Moved to...
* gimple-loop-jam.cc: ...here.
* gimple-low.c: Moved to...
* gimple-low.cc: ...here.
* gimple-match-head.c: Moved to...
* gimple-match-head.cc: ...here.
* gimple-pretty-print.c: Moved to...
* gimple-pretty-print.cc: ...here.
* gimple-ssa-backprop.c: Moved to...
* gimple-ssa-backprop.cc: ...here.
* gimple-ssa-evrp-analyze.c: Moved to...
* gimple-ssa-evrp-analyze.cc: ...here.
* gimple-ssa-evrp.c: Moved to...
* gimple-ssa-evrp.cc: ...here.
* gimple-ssa-isolate-paths.c: Moved to...
* gimple-ssa-isolate-paths.cc: ...here.
* gimple-ssa-nonnull-compare.c: Moved to...
* gimple-ssa-nonnull-compare.cc: ...here.
* gimple-ssa-split-paths.c: Moved to...
* gimple-ssa-split-paths.cc: ...here.
* gimple-ssa-sprintf.c: Moved to...
* gimple-ssa-sprintf.cc: ...here.
* gimple-ssa-store-merging.c: Moved to...
* gimple-ssa-store-merging.cc: ...here.
* gimple-ssa-strength-reduction.c: Moved to...
* gimple-ssa-strength-reduction.cc: ...here.
* gimple-ssa-warn-alloca.c: Moved to...
* gimple-ssa-warn-alloca.cc: ...here.
* gimple-ssa-warn-restrict.c: Moved to...
* gimple-ssa-warn-restrict.cc: ...here.
* gimple-streamer-in.c: Moved to...
* gimple-streamer-in.cc: ...here.
* gimple-streamer-out.c: Moved to...
* gimple-streamer-out.cc: ...here.
* gimple-walk.c: Moved to...
* gimple-walk.cc: ...here.
* gimple-warn-recursion.c: Moved to...
* gimple-warn-recursion.cc: ...here.
* gimple.c: Moved to...
* gimple.cc: ...here.
* gimplify-me.c: Moved to...
* gimplify-me.cc: ...here.
* gimplify.c: Moved to...
* gimplify.cc: ...here.
* godump.c: Moved to...
* godump.cc: ...here.
* graph.c: Moved to...
* graph.cc: ...here.
* graphds.c: Moved to...
* graphds.cc: ...here.
* graphite-dependences.c: Moved to...
* graphite-dependences.cc: ...here.
* graphite-isl-ast-to-gimple.c: Moved to...
* graphite-isl-ast-to-gimple.cc: ...here.
* graphite-optimize-isl.c: Moved to...
* graphite-optimize-isl.cc: ...here.
* graphite-poly.c: Moved to...
* graphite-poly.cc: ...here.
* graphite-scop-detection.c: Moved to...
* graphite-scop-detection.cc: ...here.
* graphite-sese-to-poly.c: Moved to...
* graphite-sese-to-poly.cc: ...here.
* graphite.c: Moved to...
* graphite.cc: ...here.
* haifa-sched.c: Moved to...
* haifa-sched.cc: ...here.
* hash-map-tests.c: Moved to...
* hash-map-tests.cc: ...here.
* hash-set-tests.c: Moved to...
* hash-set-tests.cc: ...here.
* hash-table.c: Moved to...
* hash-table.cc: ...here.
* hooks.c: Moved to...
* hooks.cc: ...here.
* host-default.c: Moved to...
* host-default.cc: ...here.
* hw-doloop.c: Moved to...
* hw-doloop.cc: ...here.
* hwint.c: Moved to...
* hwint.cc: ...here.
* ifcvt.c: Moved to...
* ifcvt.cc: ...here.
* inchash.c: Moved to...
* inchash.cc: ...here.
* incpath.c: Moved to...
* incpath.cc: ...here.
* init-regs.c: Moved to...
* init-regs.cc: ...here.
* input.c: Moved to...
* input.cc: ...here.
* internal-fn.c: Moved to...
* internal-fn.cc: ...here.
* intl.c: Moved to...
* intl.cc: ...here.
* ipa-comdats.c: Moved to...
* ipa-comdats.cc: ...here.
* ipa-cp.c: Moved to...
* ipa-cp.cc: ...here.
* ipa-devirt.c: Moved to...
* ipa-devirt.cc: ...here.
* ipa-fnsummary.c: Moved to...
* ipa-fnsummary.cc: ...here.
* ipa-icf-gimple.c: Moved to...
* ipa-icf-gimple.cc: ...here.
* ipa-icf.c: Moved to...
* ipa-icf.cc: ...here.
* ipa-inline-analysis.c: Moved to...
* ipa-inline-analysis.cc: ...here.
* ipa-inline-transform.c: Moved to...
* ipa-inline-transform.cc: ...here.
* ipa-inline.c: Moved to...
* ipa-inline.cc: ...here.
* ipa-modref-tree.c: Moved to...
* ipa-modref-tree.cc: ...here.
* ipa-modref.c: Moved to...
* ipa-modref.cc: ...here.
* ipa-param-manipulation.c: Moved to...
* ipa-param-manipulation.cc: ...here.
* ipa-polymorphic-call.c: Moved to...
* ipa-polymorphic-call.cc: ...here.
* ipa-predicate.c: Moved to...
* ipa-predicate.cc: ...here.
* ipa-profile.c: Moved to...
* ipa-profile.cc: ...here.
* ipa-prop.c: Moved to...
* ipa-prop.cc: ...here.
* ipa-pure-const.c: Moved to...
* ipa-pure-const.cc: ...here.
* ipa-ref.c: Moved to...
* ipa-ref.cc: ...here.
* ipa-reference.c: Moved to...
* ipa-reference.cc: ...here.
* ipa-split.c: Moved to...
* ipa-split.cc: ...here.
* ipa-sra.c: Moved to...
* ipa-sra.cc: ...here.
* ipa-utils.c: Moved to...
* ipa-utils.cc: ...here.
* ipa-visibility.c: Moved to...
* ipa-visibility.cc: ...here.
* ipa.c: Moved to...
* ipa.cc: ...here.
* ira-build.c: Moved to...
* ira-build.cc: ...here.
* ira-color.c: Moved to...
* ira-color.cc: ...here.
* ira-conflicts.c: Moved to...
* ira-conflicts.cc: ...here.
* ira-costs.c: Moved to...
* ira-costs.cc: ...here.
* ira-emit.c: Moved to...
* ira-emit.cc: ...here.
* ira-lives.c: Moved to...
* ira-lives.cc: ...here.
* ira.c: Moved to...
* ira.cc: ...here.
* jump.c: Moved to...
* jump.cc: ...here.
* langhooks.c: Moved to...
* langhooks.cc: ...here.
* lcm.c: Moved to...
* lcm.cc: ...here.
* lists.c: Moved to...
* lists.cc: ...here.
* loop-doloop.c: Moved to...
* loop-doloop.cc: ...here.
* loop-init.c: Moved to...
* loop-init.cc: ...here.
* loop-invariant.c: Moved to...
* loop-invariant.cc: ...here.
* loop-iv.c: Moved to...
* loop-iv.cc: ...here.
* loop-unroll.c: Moved to...
* loop-unroll.cc: ...here.
* lower-subreg.c: Moved to...
* lower-subreg.cc: ...here.
* lra-assigns.c: Moved to...
* lra-assigns.cc: ...here.
* lra-coalesce.c: Moved to...
* lra-coalesce.cc: ...here.
* lra-constraints.c: Moved to...
* lra-constraints.cc: ...here.
* lra-eliminations.c: Moved to...
* lra-eliminations.cc: ...here.
* lra-lives.c: Moved to...
* lra-lives.cc: ...here.
* lra-remat.c: Moved to...
* lra-remat.cc: ...here.
* lra-spills.c: Moved to...
* lra-spills.cc: ...here.
* lra.c: Moved to...
* lra.cc: ...here.
* lto-cgraph.c: Moved to...
* lto-cgraph.cc: ...here.
* lto-compress.c: Moved to...
* lto-compress.cc: ...here.
* lto-opts.c: Moved to...
* lto-opts.cc: ...here.
* lto-section-in.c: Moved to...
* lto-section-in.cc: ...here.
* lto-section-out.c: Moved to...
* lto-section-out.cc: ...here.
* lto-streamer-in.c: Moved to...
* lto-streamer-in.cc: ...here.
* lto-streamer-out.c: Moved to...
* lto-streamer-out.cc: ...here.
* lto-streamer.c: Moved to...
* lto-streamer.cc: ...here.
* lto-wrapper.c: Moved to...
* lto-wrapper.cc: ...here.
* main.c: Moved to...
* main.cc: ...here.
* mcf.c: Moved to...
* mcf.cc: ...here.
* mode-switching.c: Moved to...
* mode-switching.cc: ...here.
* modulo-sched.c: Moved to...
* modulo-sched.cc: ...here.
* multiple_target.c: Moved to...
* multiple_target.cc: ...here.
* omp-expand.c: Moved to...
* omp-expand.cc: ...here.
* omp-general.c: Moved to...
* omp-general.cc: ...here.
* omp-low.c: Moved to...
* omp-low.cc: ...here.
* omp-offload.c: Moved to...
* omp-offload.cc: ...here.
* omp-simd-clone.c: Moved to...
* omp-simd-clone.cc: ...here.
* opt-suggestions.c: Moved to...
* opt-suggestions.cc: ...here.
* optabs-libfuncs.c: Moved to...
* optabs-libfuncs.cc: ...here.
* optabs-query.c: Moved to...
* optabs-query.cc: ...here.
* optabs-tree.c: Moved to...
* optabs-tree.cc: ...here.
* optabs.c: Moved to...
* optabs.cc: ...here.
* opts-common.c: Moved to...
* opts-common.cc: ...here.
* opts-global.c: Moved to...
* opts-global.cc: ...here.
* opts.c: Moved to...
* opts.cc: ...here.
* passes.c: Moved to...
* passes.cc: ...here.
* plugin.c: Moved to...
* plugin.cc: ...here.
* postreload-gcse.c: Moved to...
* postreload-gcse.cc: ...here.
* postreload.c: Moved to...
* postreload.cc: ...here.
* predict.c: Moved to...
* predict.cc: ...here.
* prefix.c: Moved to...
* prefix.cc: ...here.
* pretty-print.c: Moved to...
* pretty-print.cc: ...here.
* print-rtl-function.c: Moved to...
* print-rtl-function.cc: ...here.
* print-rtl.c: Moved to...
* print-rtl.cc: ...here.
* print-tree.c: Moved to...
* print-tree.cc: ...here.
* profile-count.c: Moved to...
* profile-count.cc: ...here.
* profile.c: Moved to...
* profile.cc: ...here.
* read-md.c: Moved to...
* read-md.cc: ...here.
* read-rtl-function.c: Moved to...
* read-rtl-function.cc: ...here.
* read-rtl.c: Moved to...
* read-rtl.cc: ...here.
* real.c: Moved to...
* real.cc: ...here.
* realmpfr.c: Moved to...
* realmpfr.cc: ...here.
* recog.c: Moved to...
* recog.cc: ...here.
* ree.c: Moved to...
* ree.cc: ...here.
* reg-stack.c: Moved to...
* reg-stack.cc: ...here.
* regcprop.c: Moved to...
* regcprop.cc: ...here.
* reginfo.c: Moved to...
* reginfo.cc: ...here.
* regrename.c: Moved to...
* regrename.cc: ...here.
* regstat.c: Moved to...
* regstat.cc: ...here.
* reload.c: Moved to...
* reload.cc: ...here.
* reload1.c: Moved to...
* reload1.cc: ...here.
* reorg.c: Moved to...
* reorg.cc: ...here.
* resource.c: Moved to...
* resource.cc: ...here.
* rtl-error.c: Moved to...
* rtl-error.cc: ...here.
* rtl-tests.c: Moved to...
* rtl-tests.cc: ...here.
* rtl.c: Moved to...
* rtl.cc: ...here.
* rtlanal.c: Moved to...
* rtlanal.cc: ...here.
* rtlhash.c: Moved to...
* rtlhash.cc: ...here.
* rtlhooks.c: Moved to...
* rtlhooks.cc: ...here.
* rtx-vector-builder.c: Moved to...
* rtx-vector-builder.cc: ...here.
* run-rtl-passes.c: Moved to...
* run-rtl-passes.cc: ...here.
* sancov.c: Moved to...
* sancov.cc: ...here.
* sanopt.c: Moved to...
* sanopt.cc: ...here.
* sbitmap.c: Moved to...
* sbitmap.cc: ...here.
* sched-deps.c: Moved to...
* sched-deps.cc: ...here.
* sched-ebb.c: Moved to...
* sched-ebb.cc: ...here.
* sched-rgn.c: Moved to...
* sched-rgn.cc: ...here.
* sel-sched-dump.c: Moved to...
* sel-sched-dump.cc: ...here.
* sel-sched-ir.c: Moved to...
* sel-sched-ir.cc: ...here.
* sel-sched.c: Moved to...
* sel-sched.cc: ...here.
* selftest-diagnostic.c: Moved to...
* selftest-diagnostic.cc: ...here.
* selftest-rtl.c: Moved to...
* selftest-rtl.cc: ...here.
* selftest-run-tests.c: Moved to...
* selftest-run-tests.cc: ...here.
* selftest.c: Moved to...
* selftest.cc: ...here.
* sese.c: Moved to...
* sese.cc: ...here.
* shrink-wrap.c: Moved to...
* shrink-wrap.cc: ...here.
* simplify-rtx.c: Moved to...
* simplify-rtx.cc: ...here.
* sparseset.c: Moved to...
* sparseset.cc: ...here.
* spellcheck-tree.c: Moved to...
* spellcheck-tree.cc: ...here.
* spellcheck.c: Moved to...
* spellcheck.cc: ...here.
* sreal.c: Moved to...
* sreal.cc: ...here.
* stack-ptr-mod.c: Moved to...
* stack-ptr-mod.cc: ...here.
* statistics.c: Moved to...
* statistics.cc: ...here.
* stmt.c: Moved to...
* stmt.cc: ...here.
* stor-layout.c: Moved to...
* stor-layout.cc: ...here.
* store-motion.c: Moved to...
* store-motion.cc: ...here.
* streamer-hooks.c: Moved to...
* streamer-hooks.cc: ...here.
* stringpool.c: Moved to...
* stringpool.cc: ...here.
* substring-locations.c: Moved to...
* substring-locations.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* target-globals.c: Moved to...
* target-globals.cc: ...here.
* targhooks.c: Moved to...
* targhooks.cc: ...here.
* timevar.c: Moved to...
* timevar.cc: ...here.
* toplev.c: Moved to...
* toplev.cc: ...here.
* tracer.c: Moved to...
* tracer.cc: ...here.
* trans-mem.c: Moved to...
* trans-mem.cc: ...here.
* tree-affine.c: Moved to...
* tree-affine.cc: ...here.
* tree-call-cdce.c: Moved to...
* tree-call-cdce.cc: ...here.
* tree-cfg.c: Moved to...
* tree-cfg.cc: ...here.
* tree-cfgcleanup.c: Moved to...
* tree-cfgcleanup.cc: ...here.
* tree-chrec.c: Moved to...
* tree-chrec.cc: ...here.
* tree-complex.c: Moved to...
* tree-complex.cc: ...here.
* tree-data-ref.c: Moved to...
* tree-data-ref.cc: ...here.
* tree-dfa.c: Moved to...
* tree-dfa.cc: ...here.
* tree-diagnostic.c: Moved to...
* tree-diagnostic.cc: ...here.
* tree-dump.c: Moved to...
* tree-dump.cc: ...here.
* tree-eh.c: Moved to...
* tree-eh.cc: ...here.
* tree-emutls.c: Moved to...
* tree-emutls.cc: ...here.
* tree-if-conv.c: Moved to...
* tree-if-conv.cc: ...here.
* tree-inline.c: Moved to...
* tree-inline.cc: ...here.
* tree-into-ssa.c: Moved to...
* tree-into-ssa.cc: ...here.
* tree-iterator.c: Moved to...
* tree-iterator.cc: ...here.
* tree-loop-distribution.c: Moved to...
* tree-loop-distribution.cc: ...here.
* tree-nested.c: Moved to...
* tree-nested.cc: ...here.
* tree-nrv.c: Moved to...
* tree-nrv.cc: ...here.
* tree-object-size.c: Moved to...
* tree-object-size.cc: ...here.
* tree-outof-ssa.c: Moved to...
* tree-outof-ssa.cc: ...here.
* tree-parloops.c: Moved to...
* tree-parloops.cc: ...here.
* tree-phinodes.c: Moved to...
* tree-phinodes.cc: ...here.
* tree-predcom.c: Moved to...
* tree-predcom.cc: ...here.
* tree-pretty-print.c: Moved to...
* tree-pretty-print.cc: ...here.
* tree-profile.c: Moved to...
* tree-profile.cc: ...here.
* tree-scalar-evolution.c: Moved to...
* tree-scalar-evolution.cc: ...here.
* tree-sra.c: Moved to...
* tree-sra.cc: ...here.
* tree-ssa-address.c: Moved to...
* tree-ssa-address.cc: ...here.
* tree-ssa-alias.c: Moved to...
* tree-ssa-alias.cc: ...here.
* tree-ssa-ccp.c: Moved to...
* tree-ssa-ccp.cc: ...here.
* tree-ssa-coalesce.c: Moved to...
* tree-ssa-coalesce.cc: ...here.
* tree-ssa-copy.c: Moved to...
* tree-ssa-copy.cc: ...here.
* tree-ssa-dce.c: Moved to...
* tree-ssa-dce.cc: ...here.
* tree-ssa-dom.c: Moved to...
* tree-ssa-dom.cc: ...here.
* tree-ssa-dse.c: Moved to...
* tree-ssa-dse.cc: ...here.
* tree-ssa-forwprop.c: Moved to...
* tree-ssa-forwprop.cc: ...here.
* tree-ssa-ifcombine.c: Moved to...
* tree-ssa-ifcombine.cc: ...here.
* tree-ssa-live.c: Moved to...
* tree-ssa-live.cc: ...here.
* tree-ssa-loop-ch.c: Moved to...
* tree-ssa-loop-ch.cc: ...here.
* tree-ssa-loop-im.c: Moved to...
* tree-ssa-loop-im.cc: ...here.
* tree-ssa-loop-ivcanon.c: Moved to...
* tree-ssa-loop-ivcanon.cc: ...here.
* tree-ssa-loop-ivopts.c: Moved to...
* tree-ssa-loop-ivopts.cc: ...here.
* tree-ssa-loop-manip.c: Moved to...
* tree-ssa-loop-manip.cc: ...here.
* tree-ssa-loop-niter.c: Moved to...
* tree-ssa-loop-niter.cc: ...here.
* tree-ssa-loop-prefetch.c: Moved to...
* tree-ssa-loop-prefetch.cc: ...here.
* tree-ssa-loop-split.c: Moved to...
* tree-ssa-loop-split.cc: ...here.
* tree-ssa-loop-unswitch.c: Moved to...
* tree-ssa-loop-unswitch.cc: ...here.
* tree-ssa-loop.c: Moved to...
* tree-ssa-loop.cc: ...here.
* tree-ssa-math-opts.c: Moved to...
* tree-ssa-math-opts.cc: ...here.
* tree-ssa-operands.c: Moved to...
* tree-ssa-operands.cc: ...here.
* tree-ssa-phiopt.c: Moved to...
* tree-ssa-phiopt.cc: ...here.
* tree-ssa-phiprop.c: Moved to...
* tree-ssa-phiprop.cc: ...here.
* tree-ssa-pre.c: Moved to...
* tree-ssa-pre.cc: ...here.
* tree-ssa-propagate.c: Moved to...
* tree-ssa-propagate.cc: ...here.
* tree-ssa-reassoc.c: Moved to...
* tree-ssa-reassoc.cc: ...here.
* tree-ssa-sccvn.c: Moved to...
* tree-ssa-sccvn.cc: ...here.
* tree-ssa-scopedtables.c: Moved to...
* tree-ssa-scopedtables.cc: ...here.
* tree-ssa-sink.c: Moved to...
* tree-ssa-sink.cc: ...here.
* tree-ssa-strlen.c: Moved to...
* tree-ssa-strlen.cc: ...here.
* tree-ssa-structalias.c: Moved to...
* tree-ssa-structalias.cc: ...here.
* tree-ssa-tail-merge.c: Moved to...
* tree-ssa-tail-merge.cc: ...here.
* tree-ssa-ter.c: Moved to...
* tree-ssa-ter.cc: ...here.
* tree-ssa-threadbackward.c: Moved to...
* tree-ssa-threadbackward.cc: ...here.
* tree-ssa-threadedge.c: Moved to...
* tree-ssa-threadedge.cc: ...here.
* tree-ssa-threadupdate.c: Moved to...
* tree-ssa-threadupdate.cc: ...here.
* tree-ssa-uncprop.c: Moved to...
* tree-ssa-uncprop.cc: ...here.
* tree-ssa-uninit.c: Moved to...
* tree-ssa-uninit.cc: ...here.
* tree-ssa.c: Moved to...
* tree-ssa.cc: ...here.
* tree-ssanames.c: Moved to...
* tree-ssanames.cc: ...here.
* tree-stdarg.c: Moved to...
* tree-stdarg.cc: ...here.
* tree-streamer-in.c: Moved to...
* tree-streamer-in.cc: ...here.
* tree-streamer-out.c: Moved to...
* tree-streamer-out.cc: ...here.
* tree-streamer.c: Moved to...
* tree-streamer.cc: ...here.
* tree-switch-conversion.c: Moved to...
* tree-switch-conversion.cc: ...here.
* tree-tailcall.c: Moved to...
* tree-tailcall.cc: ...here.
* tree-vect-data-refs.c: Moved to...
* tree-vect-data-refs.cc: ...here.
* tree-vect-generic.c: Moved to...
* tree-vect-generic.cc: ...here.
* tree-vect-loop-manip.c: Moved to...
* tree-vect-loop-manip.cc: ...here.
* tree-vect-loop.c: Moved to...
* tree-vect-loop.cc: ...here.
* tree-vect-patterns.c: Moved to...
* tree-vect-patterns.cc: ...here.
* tree-vect-slp-patterns.c: Moved to...
* tree-vect-slp-patterns.cc: ...here.
* tree-vect-slp.c: Moved to...
* tree-vect-slp.cc: ...here.
* tree-vect-stmts.c: Moved to...
* tree-vect-stmts.cc: ...here.
* tree-vector-builder.c: Moved to...
* tree-vector-builder.cc: ...here.
* tree-vectorizer.c: Moved to...
* tree-vectorizer.cc: ...here.
* tree-vrp.c: Moved to...
* tree-vrp.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* tsan.c: Moved to...
* tsan.cc: ...here.
* typed-splay-tree.c: Moved to...
* typed-splay-tree.cc: ...here.
* ubsan.c: Moved to...
* ubsan.cc: ...here.
* valtrack.c: Moved to...
* valtrack.cc: ...here.
* value-prof.c: Moved to...
* value-prof.cc: ...here.
* var-tracking.c: Moved to...
* var-tracking.cc: ...here.
* varasm.c: Moved to...
* varasm.cc: ...here.
* varpool.c: Moved to...
* varpool.cc: ...here.
* vec-perm-indices.c: Moved to...
* vec-perm-indices.cc: ...here.
* vec.c: Moved to...
* vec.cc: ...here.
* vmsdbgout.c: Moved to...
* vmsdbgout.cc: ...here.
* vr-values.c: Moved to...
* vr-values.cc: ...here.
* vtable-verify.c: Moved to...
* vtable-verify.cc: ...here.
* web.c: Moved to...
* web.cc: ...here.
* xcoffout.c: Moved to...
* xcoffout.cc: ...here.
gcc/c-family/ChangeLog:
* c-ada-spec.c: Moved to...
* c-ada-spec.cc: ...here.
* c-attribs.c: Moved to...
* c-attribs.cc: ...here.
* c-common.c: Moved to...
* c-common.cc: ...here.
* c-cppbuiltin.c: Moved to...
* c-cppbuiltin.cc: ...here.
* c-dump.c: Moved to...
* c-dump.cc: ...here.
* c-format.c: Moved to...
* c-format.cc: ...here.
* c-gimplify.c: Moved to...
* c-gimplify.cc: ...here.
* c-indentation.c: Moved to...
* c-indentation.cc: ...here.
* c-lex.c: Moved to...
* c-lex.cc: ...here.
* c-omp.c: Moved to...
* c-omp.cc: ...here.
* c-opts.c: Moved to...
* c-opts.cc: ...here.
* c-pch.c: Moved to...
* c-pch.cc: ...here.
* c-ppoutput.c: Moved to...
* c-ppoutput.cc: ...here.
* c-pragma.c: Moved to...
* c-pragma.cc: ...here.
* c-pretty-print.c: Moved to...
* c-pretty-print.cc: ...here.
* c-semantics.c: Moved to...
* c-semantics.cc: ...here.
* c-ubsan.c: Moved to...
* c-ubsan.cc: ...here.
* c-warn.c: Moved to...
* c-warn.cc: ...here.
* cppspec.c: Moved to...
* cppspec.cc: ...here.
* stub-objc.c: Moved to...
* stub-objc.cc: ...here.
gcc/c/ChangeLog:
* c-aux-info.c: Moved to...
* c-aux-info.cc: ...here.
* c-convert.c: Moved to...
* c-convert.cc: ...here.
* c-decl.c: Moved to...
* c-decl.cc: ...here.
* c-errors.c: Moved to...
* c-errors.cc: ...here.
* c-fold.c: Moved to...
* c-fold.cc: ...here.
* c-lang.c: Moved to...
* c-lang.cc: ...here.
* c-objc-common.c: Moved to...
* c-objc-common.cc: ...here.
* c-parser.c: Moved to...
* c-parser.cc: ...here.
* c-typeck.c: Moved to...
* c-typeck.cc: ...here.
* gccspec.c: Moved to...
* gccspec.cc: ...here.
* gimple-parser.c: Moved to...
* gimple-parser.cc: ...here.
gcc/cp/ChangeLog:
* call.c: Moved to...
* call.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constexpr.c: Moved to...
* constexpr.cc: ...here.
* cp-gimplify.c: Moved to...
* cp-gimplify.cc: ...here.
* cp-lang.c: Moved to...
* cp-lang.cc: ...here.
* cp-objcp-common.c: Moved to...
* cp-objcp-common.cc: ...here.
* cp-ubsan.c: Moved to...
* cp-ubsan.cc: ...here.
* cvt.c: Moved to...
* cvt.cc: ...here.
* cxx-pretty-print.c: Moved to...
* cxx-pretty-print.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* decl2.c: Moved to...
* decl2.cc: ...here.
* dump.c: Moved to...
* dump.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* friend.c: Moved to...
* friend.cc: ...here.
* g++spec.c: Moved to...
* g++spec.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lambda.c: Moved to...
* lambda.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* mangle.c: Moved to...
* mangle.cc: ...here.
* method.c: Moved to...
* method.cc: ...here.
* name-lookup.c: Moved to...
* name-lookup.cc: ...here.
* optimize.c: Moved to...
* optimize.cc: ...here.
* parser.c: Moved to...
* parser.cc: ...here.
* pt.c: Moved to...
* pt.cc: ...here.
* ptree.c: Moved to...
* ptree.cc: ...here.
* rtti.c: Moved to...
* rtti.cc: ...here.
* search.c: Moved to...
* search.cc: ...here.
* semantics.c: Moved to...
* semantics.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* typeck.c: Moved to...
* typeck.cc: ...here.
* typeck2.c: Moved to...
* typeck2.cc: ...here.
* vtable-class-hierarchy.c: Moved to...
* vtable-class-hierarchy.cc: ...here.
gcc/fortran/ChangeLog:
* arith.c: Moved to...
* arith.cc: ...here.
* array.c: Moved to...
* array.cc: ...here.
* bbt.c: Moved to...
* bbt.cc: ...here.
* check.c: Moved to...
* check.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constructor.c: Moved to...
* constructor.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* cpp.c: Moved to...
* cpp.cc: ...here.
* data.c: Moved to...
* data.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* dependency.c: Moved to...
* dependency.cc: ...here.
* dump-parse-tree.c: Moved to...
* dump-parse-tree.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* f95-lang.c: Moved to...
* f95-lang.cc: ...here.
* frontend-passes.c: Moved to...
* frontend-passes.cc: ...here.
* gfortranspec.c: Moved to...
* gfortranspec.cc: ...here.
* interface.c: Moved to...
* interface.cc: ...here.
* intrinsic.c: Moved to...
* intrinsic.cc: ...here.
* io.c: Moved to...
* io.cc: ...here.
* iresolve.c: Moved to...
* iresolve.cc: ...here.
* match.c: Moved to...
* match.cc: ...here.
* matchexp.c: Moved to...
* matchexp.cc: ...here.
* misc.c: Moved to...
* misc.cc: ...here.
* module.c: Moved to...
* module.cc: ...here.
* openmp.c: Moved to...
* openmp.cc: ...here.
* options.c: Moved to...
* options.cc: ...here.
* parse.c: Moved to...
* parse.cc: ...here.
* primary.c: Moved to...
* primary.cc: ...here.
* resolve.c: Moved to...
* resolve.cc: ...here.
* scanner.c: Moved to...
* scanner.cc: ...here.
* simplify.c: Moved to...
* simplify.cc: ...here.
* st.c: Moved to...
* st.cc: ...here.
* symbol.c: Moved to...
* symbol.cc: ...here.
* target-memory.c: Moved to...
* target-memory.cc: ...here.
* trans-array.c: Moved to...
* trans-array.cc: ...here.
* trans-common.c: Moved to...
* trans-common.cc: ...here.
* trans-const.c: Moved to...
* trans-const.cc: ...here.
* trans-decl.c: Moved to...
* trans-decl.cc: ...here.
* trans-expr.c: Moved to...
* trans-expr.cc: ...here.
* trans-intrinsic.c: Moved to...
* trans-intrinsic.cc: ...here.
* trans-io.c: Moved to...
* trans-io.cc: ...here.
* trans-openmp.c: Moved to...
* trans-openmp.cc: ...here.
* trans-stmt.c: Moved to...
* trans-stmt.cc: ...here.
* trans-types.c: Moved to...
* trans-types.cc: ...here.
* trans.c: Moved to...
* trans.cc: ...here.
gcc/go/ChangeLog:
* go-backend.c: Moved to...
* go-backend.cc: ...here.
* go-lang.c: Moved to...
* go-lang.cc: ...here.
* gospec.c: Moved to...
* gospec.cc: ...here.
gcc/jit/ChangeLog:
* dummy-frontend.c: Moved to...
* dummy-frontend.cc: ...here.
* jit-builtins.c: Moved to...
* jit-builtins.cc: ...here.
* jit-logging.c: Moved to...
* jit-logging.cc: ...here.
* jit-playback.c: Moved to...
* jit-playback.cc: ...here.
* jit-recording.c: Moved to...
* jit-recording.cc: ...here.
* jit-result.c: Moved to...
* jit-result.cc: ...here.
* jit-spec.c: Moved to...
* jit-spec.cc: ...here.
* jit-tempdir.c: Moved to...
* jit-tempdir.cc: ...here.
* jit-w32.c: Moved to...
* jit-w32.cc: ...here.
* libgccjit.c: Moved to...
* libgccjit.cc: ...here.
gcc/lto/ChangeLog:
* common.c: Moved to...
* common.cc: ...here.
* lto-common.c: Moved to...
* lto-common.cc: ...here.
* lto-dump.c: Moved to...
* lto-dump.cc: ...here.
* lto-lang.c: Moved to...
* lto-lang.cc: ...here.
* lto-object.c: Moved to...
* lto-object.cc: ...here.
* lto-partition.c: Moved to...
* lto-partition.cc: ...here.
* lto-symtab.c: Moved to...
* lto-symtab.cc: ...here.
* lto.c: Moved to...
* lto.cc: ...here.
gcc/objc/ChangeLog:
* objc-act.c: Moved to...
* objc-act.cc: ...here.
* objc-encoding.c: Moved to...
* objc-encoding.cc: ...here.
* objc-gnu-runtime-abi-01.c: Moved to...
* objc-gnu-runtime-abi-01.cc: ...here.
* objc-lang.c: Moved to...
* objc-lang.cc: ...here.
* objc-map.c: Moved to...
* objc-map.cc: ...here.
* objc-next-runtime-abi-01.c: Moved to...
* objc-next-runtime-abi-01.cc: ...here.
* objc-next-runtime-abi-02.c: Moved to...
* objc-next-runtime-abi-02.cc: ...here.
* objc-runtime-shared-support.c: Moved to...
* objc-runtime-shared-support.cc: ...here.
gcc/objcp/ChangeLog:
* objcp-decl.c: Moved to...
* objcp-decl.cc: ...here.
* objcp-lang.c: Moved to...
* objcp-lang.cc: ...here.
libcpp/ChangeLog:
* charset.c: Moved to...
* charset.cc: ...here.
* directives.c: Moved to...
* directives.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* files.c: Moved to...
* files.cc: ...here.
* identifiers.c: Moved to...
* identifiers.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* line-map.c: Moved to...
* line-map.cc: ...here.
* macro.c: Moved to...
* macro.cc: ...here.
* makeucnid.c: Moved to...
* makeucnid.cc: ...here.
* mkdeps.c: Moved to...
* mkdeps.cc: ...here.
* pch.c: Moved to...
* pch.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* traditional.c: Moved to...
* traditional.cc: ...here.
Diffstat (limited to 'gcc/ifcvt.c')
-rw-r--r-- | gcc/ifcvt.c | 5694 |
1 files changed, 0 insertions, 5694 deletions
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c deleted file mode 100644 index 9a3e453..0000000 --- a/gcc/ifcvt.c +++ /dev/null @@ -1,5694 +0,0 @@ -/* If-conversion support. - Copyright (C) 2000-2022 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING3. If not see - <http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "target.h" -#include "rtl.h" -#include "tree.h" -#include "cfghooks.h" -#include "df.h" -#include "memmodel.h" -#include "tm_p.h" -#include "expmed.h" -#include "optabs.h" -#include "regs.h" -#include "emit-rtl.h" -#include "recog.h" - -#include "cfgrtl.h" -#include "cfganal.h" -#include "cfgcleanup.h" -#include "expr.h" -#include "output.h" -#include "cfgloop.h" -#include "tree-pass.h" -#include "dbgcnt.h" -#include "shrink-wrap.h" -#include "rtl-iter.h" -#include "ifcvt.h" - -#ifndef MAX_CONDITIONAL_EXECUTE -#define MAX_CONDITIONAL_EXECUTE \ - (BRANCH_COST (optimize_function_for_speed_p (cfun), false) \ - + 1) -#endif - -#define IFCVT_MULTIPLE_DUMPS 1 - -#define NULL_BLOCK ((basic_block) NULL) - -/* True if after combine pass. */ -static bool ifcvt_after_combine; - -/* True if the target has the cbranchcc4 optab. */ -static bool have_cbranchcc4; - -/* # of IF-THEN or IF-THEN-ELSE blocks we looked at */ -static int num_possible_if_blocks; - -/* # of IF-THEN or IF-THEN-ELSE blocks were converted to conditional - execution. */ -static int num_updated_if_blocks; - -/* # of changes made. */ -static int num_true_changes; - -/* Whether conditional execution changes were made. */ -static int cond_exec_changed_p; - -/* Forward references. */ -static int count_bb_insns (const_basic_block); -static bool cheap_bb_rtx_cost_p (const_basic_block, profile_probability, int); -static rtx_insn *first_active_insn (basic_block); -static rtx_insn *last_active_insn (basic_block, int); -static rtx_insn *find_active_insn_before (basic_block, rtx_insn *); -static rtx_insn *find_active_insn_after (basic_block, rtx_insn *); -static basic_block block_fallthru (basic_block); -static rtx cond_exec_get_condition (rtx_insn *); -static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool); -static int noce_operand_ok (const_rtx); -static void merge_if_block (ce_if_block *); -static int find_cond_trap (basic_block, edge, edge); -static basic_block find_if_header (basic_block, int); -static int block_jumps_and_fallthru_p (basic_block, basic_block); -static int noce_find_if_block (basic_block, edge, edge, int); -static int cond_exec_find_if_block (ce_if_block *); -static int find_if_case_1 (basic_block, edge, edge); -static int find_if_case_2 (basic_block, edge, edge); -static int dead_or_predicable (basic_block, basic_block, basic_block, - edge, int); -static void noce_emit_move_insn (rtx, rtx); -static rtx_insn *block_has_only_trap (basic_block); - -/* Count the number of non-jump active insns in BB. */ - -static int -count_bb_insns (const_basic_block bb) -{ - int count = 0; - rtx_insn *insn = BB_HEAD (bb); - - while (1) - { - if (active_insn_p (insn) && !JUMP_P (insn)) - count++; - - if (insn == BB_END (bb)) - break; - insn = NEXT_INSN (insn); - } - - return count; -} - -/* Determine whether the total insn_cost on non-jump insns in - basic block BB is less than MAX_COST. This function returns - false if the cost of any instruction could not be estimated. - - The cost of the non-jump insns in BB is scaled by REG_BR_PROB_BASE - as those insns are being speculated. MAX_COST is scaled with SCALE - plus a small fudge factor. */ - -static bool -cheap_bb_rtx_cost_p (const_basic_block bb, - profile_probability prob, int max_cost) -{ - int count = 0; - rtx_insn *insn = BB_HEAD (bb); - bool speed = optimize_bb_for_speed_p (bb); - int scale = prob.initialized_p () ? prob.to_reg_br_prob_base () - : REG_BR_PROB_BASE; - - /* Set scale to REG_BR_PROB_BASE to void the identical scaling - applied to insn_cost when optimizing for size. Only do - this after combine because if-conversion might interfere with - passes before combine. - - Use optimize_function_for_speed_p instead of the pre-defined - variable speed to make sure it is set to same value for all - basic blocks in one if-conversion transformation. */ - if (!optimize_function_for_speed_p (cfun) && ifcvt_after_combine) - scale = REG_BR_PROB_BASE; - /* Our branch probability/scaling factors are just estimates and don't - account for cases where we can get speculation for free and other - secondary benefits. So we fudge the scale factor to make speculating - appear a little more profitable when optimizing for performance. */ - else - scale += REG_BR_PROB_BASE / 8; - - - max_cost *= scale; - - while (1) - { - if (NONJUMP_INSN_P (insn)) - { - int cost = insn_cost (insn, speed) * REG_BR_PROB_BASE; - if (cost == 0) - return false; - - /* If this instruction is the load or set of a "stack" register, - such as a floating point register on x87, then the cost of - speculatively executing this insn may need to include - the additional cost of popping its result off of the - register stack. Unfortunately, correctly recognizing and - accounting for this additional overhead is tricky, so for - now we simply prohibit such speculative execution. */ -#ifdef STACK_REGS - { - rtx set = single_set (insn); - if (set && STACK_REG_P (SET_DEST (set))) - return false; - } -#endif - - count += cost; - if (count >= max_cost) - return false; - } - else if (CALL_P (insn)) - return false; - - if (insn == BB_END (bb)) - break; - insn = NEXT_INSN (insn); - } - - return true; -} - -/* Return the first non-jump active insn in the basic block. */ - -static rtx_insn * -first_active_insn (basic_block bb) -{ - rtx_insn *insn = BB_HEAD (bb); - - if (LABEL_P (insn)) - { - if (insn == BB_END (bb)) - return NULL; - insn = NEXT_INSN (insn); - } - - while (NOTE_P (insn) || DEBUG_INSN_P (insn)) - { - if (insn == BB_END (bb)) - return NULL; - insn = NEXT_INSN (insn); - } - - if (JUMP_P (insn)) - return NULL; - - return insn; -} - -/* Return the last non-jump active (non-jump) insn in the basic block. */ - -static rtx_insn * -last_active_insn (basic_block bb, int skip_use_p) -{ - rtx_insn *insn = BB_END (bb); - rtx_insn *head = BB_HEAD (bb); - - while (NOTE_P (insn) - || JUMP_P (insn) - || DEBUG_INSN_P (insn) - || (skip_use_p - && NONJUMP_INSN_P (insn) - && GET_CODE (PATTERN (insn)) == USE)) - { - if (insn == head) - return NULL; - insn = PREV_INSN (insn); - } - - if (LABEL_P (insn)) - return NULL; - - return insn; -} - -/* Return the active insn before INSN inside basic block CURR_BB. */ - -static rtx_insn * -find_active_insn_before (basic_block curr_bb, rtx_insn *insn) -{ - if (!insn || insn == BB_HEAD (curr_bb)) - return NULL; - - while ((insn = PREV_INSN (insn)) != NULL_RTX) - { - if (NONJUMP_INSN_P (insn) || JUMP_P (insn) || CALL_P (insn)) - break; - - /* No other active insn all the way to the start of the basic block. */ - if (insn == BB_HEAD (curr_bb)) - return NULL; - } - - return insn; -} - -/* Return the active insn after INSN inside basic block CURR_BB. */ - -static rtx_insn * -find_active_insn_after (basic_block curr_bb, rtx_insn *insn) -{ - if (!insn || insn == BB_END (curr_bb)) - return NULL; - - while ((insn = NEXT_INSN (insn)) != NULL_RTX) - { - if (NONJUMP_INSN_P (insn) || JUMP_P (insn) || CALL_P (insn)) - break; - - /* No other active insn all the way to the end of the basic block. */ - if (insn == BB_END (curr_bb)) - return NULL; - } - - return insn; -} - -/* Return the basic block reached by falling though the basic block BB. */ - -static basic_block -block_fallthru (basic_block bb) -{ - edge e = find_fallthru_edge (bb->succs); - - return (e) ? e->dest : NULL_BLOCK; -} - -/* Return true if RTXs A and B can be safely interchanged. */ - -static bool -rtx_interchangeable_p (const_rtx a, const_rtx b) -{ - if (!rtx_equal_p (a, b)) - return false; - - if (GET_CODE (a) != MEM) - return true; - - /* A dead type-unsafe memory reference is legal, but a live type-unsafe memory - reference is not. Interchanging a dead type-unsafe memory reference with - a live type-safe one creates a live type-unsafe memory reference, in other - words, it makes the program illegal. - We check here conservatively whether the two memory references have equal - memory attributes. */ - - return mem_attrs_eq_p (get_mem_attrs (a), get_mem_attrs (b)); -} - - -/* Go through a bunch of insns, converting them to conditional - execution format if possible. Return TRUE if all of the non-note - insns were processed. */ - -static int -cond_exec_process_insns (ce_if_block *ce_info ATTRIBUTE_UNUSED, - /* if block information */rtx_insn *start, - /* first insn to look at */rtx end, - /* last insn to look at */rtx test, - /* conditional execution test */profile_probability - prob_val, - /* probability of branch taken. */int mod_ok) -{ - int must_be_last = FALSE; - rtx_insn *insn; - rtx xtest; - rtx pattern; - - if (!start || !end) - return FALSE; - - for (insn = start; ; insn = NEXT_INSN (insn)) - { - /* dwarf2out can't cope with conditional prologues. */ - if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END) - return FALSE; - - if (NOTE_P (insn) || DEBUG_INSN_P (insn)) - goto insn_done; - - gcc_assert (NONJUMP_INSN_P (insn) || CALL_P (insn)); - - /* dwarf2out can't cope with conditional unwind info. */ - if (RTX_FRAME_RELATED_P (insn)) - return FALSE; - - /* Remove USE insns that get in the way. */ - if (reload_completed && GET_CODE (PATTERN (insn)) == USE) - { - /* ??? Ug. Actually unlinking the thing is problematic, - given what we'd have to coordinate with our callers. */ - SET_INSN_DELETED (insn); - goto insn_done; - } - - /* Last insn wasn't last? */ - if (must_be_last) - return FALSE; - - if (modified_in_p (test, insn)) - { - if (!mod_ok) - return FALSE; - must_be_last = TRUE; - } - - /* Now build the conditional form of the instruction. */ - pattern = PATTERN (insn); - xtest = copy_rtx (test); - - /* If this is already a COND_EXEC, rewrite the test to be an AND of the - two conditions. */ - if (GET_CODE (pattern) == COND_EXEC) - { - if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern))) - return FALSE; - - xtest = gen_rtx_AND (GET_MODE (xtest), xtest, - COND_EXEC_TEST (pattern)); - pattern = COND_EXEC_CODE (pattern); - } - - pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern); - - /* If the machine needs to modify the insn being conditionally executed, - say for example to force a constant integer operand into a temp - register, do so here. */ -#ifdef IFCVT_MODIFY_INSN - IFCVT_MODIFY_INSN (ce_info, pattern, insn); - if (! pattern) - return FALSE; -#endif - - validate_change (insn, &PATTERN (insn), pattern, 1); - - if (CALL_P (insn) && prob_val.initialized_p ()) - validate_change (insn, ®_NOTES (insn), - gen_rtx_INT_LIST ((machine_mode) REG_BR_PROB, - prob_val.to_reg_br_prob_note (), - REG_NOTES (insn)), 1); - - insn_done: - if (insn == end) - break; - } - - return TRUE; -} - -/* Return the condition for a jump. Do not do any special processing. */ - -static rtx -cond_exec_get_condition (rtx_insn *jump) -{ - rtx test_if, cond; - - if (any_condjump_p (jump)) - test_if = SET_SRC (pc_set (jump)); - else - return NULL_RTX; - cond = XEXP (test_if, 0); - - /* If this branches to JUMP_LABEL when the condition is false, - reverse the condition. */ - if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF - && label_ref_label (XEXP (test_if, 2)) == JUMP_LABEL (jump)) - { - enum rtx_code rev = reversed_comparison_code (cond, jump); - if (rev == UNKNOWN) - return NULL_RTX; - - cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0), - XEXP (cond, 1)); - } - - return cond; -} - -/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it - to conditional execution. Return TRUE if we were successful at - converting the block. */ - -static int -cond_exec_process_if_block (ce_if_block * ce_info, - /* if block information */int do_multiple_p) -{ - basic_block test_bb = ce_info->test_bb; /* last test block */ - basic_block then_bb = ce_info->then_bb; /* THEN */ - basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */ - rtx test_expr; /* expression in IF_THEN_ELSE that is tested */ - rtx_insn *then_start; /* first insn in THEN block */ - rtx_insn *then_end; /* last insn + 1 in THEN block */ - rtx_insn *else_start = NULL; /* first insn in ELSE block or NULL */ - rtx_insn *else_end = NULL; /* last insn + 1 in ELSE block */ - int max; /* max # of insns to convert. */ - int then_mod_ok; /* whether conditional mods are ok in THEN */ - rtx true_expr; /* test for else block insns */ - rtx false_expr; /* test for then block insns */ - profile_probability true_prob_val;/* probability of else block */ - profile_probability false_prob_val;/* probability of then block */ - rtx_insn *then_last_head = NULL; /* Last match at the head of THEN */ - rtx_insn *else_last_head = NULL; /* Last match at the head of ELSE */ - rtx_insn *then_first_tail = NULL; /* First match at the tail of THEN */ - rtx_insn *else_first_tail = NULL; /* First match at the tail of ELSE */ - int then_n_insns, else_n_insns, n_insns; - enum rtx_code false_code; - rtx note; - - /* If test is comprised of && or || elements, and we've failed at handling - all of them together, just use the last test if it is the special case of - && elements without an ELSE block. */ - if (!do_multiple_p && ce_info->num_multiple_test_blocks) - { - if (else_bb || ! ce_info->and_and_p) - return FALSE; - - ce_info->test_bb = test_bb = ce_info->last_test_bb; - ce_info->num_multiple_test_blocks = 0; - ce_info->num_and_and_blocks = 0; - ce_info->num_or_or_blocks = 0; - } - - /* Find the conditional jump to the ELSE or JOIN part, and isolate - the test. */ - test_expr = cond_exec_get_condition (BB_END (test_bb)); - if (! test_expr) - return FALSE; - - /* If the conditional jump is more than just a conditional jump, - then we cannot do conditional execution conversion on this block. */ - if (! onlyjump_p (BB_END (test_bb))) - return FALSE; - - /* Collect the bounds of where we're to search, skipping any labels, jumps - and notes at the beginning and end of the block. Then count the total - number of insns and see if it is small enough to convert. */ - then_start = first_active_insn (then_bb); - then_end = last_active_insn (then_bb, TRUE); - then_n_insns = ce_info->num_then_insns = count_bb_insns (then_bb); - n_insns = then_n_insns; - max = MAX_CONDITIONAL_EXECUTE; - - if (else_bb) - { - int n_matching; - - max *= 2; - else_start = first_active_insn (else_bb); - else_end = last_active_insn (else_bb, TRUE); - else_n_insns = ce_info->num_else_insns = count_bb_insns (else_bb); - n_insns += else_n_insns; - - /* Look for matching sequences at the head and tail of the two blocks, - and limit the range of insns to be converted if possible. */ - n_matching = flow_find_cross_jump (then_bb, else_bb, - &then_first_tail, &else_first_tail, - NULL); - if (then_first_tail == BB_HEAD (then_bb)) - then_start = then_end = NULL; - if (else_first_tail == BB_HEAD (else_bb)) - else_start = else_end = NULL; - - if (n_matching > 0) - { - if (then_end) - then_end = find_active_insn_before (then_bb, then_first_tail); - if (else_end) - else_end = find_active_insn_before (else_bb, else_first_tail); - n_insns -= 2 * n_matching; - } - - if (then_start - && else_start - && then_n_insns > n_matching - && else_n_insns > n_matching) - { - int longest_match = MIN (then_n_insns - n_matching, - else_n_insns - n_matching); - n_matching - = flow_find_head_matching_sequence (then_bb, else_bb, - &then_last_head, - &else_last_head, - longest_match); - - if (n_matching > 0) - { - rtx_insn *insn; - - /* We won't pass the insns in the head sequence to - cond_exec_process_insns, so we need to test them here - to make sure that they don't clobber the condition. */ - for (insn = BB_HEAD (then_bb); - insn != NEXT_INSN (then_last_head); - insn = NEXT_INSN (insn)) - if (!LABEL_P (insn) && !NOTE_P (insn) - && !DEBUG_INSN_P (insn) - && modified_in_p (test_expr, insn)) - return FALSE; - } - - if (then_last_head == then_end) - then_start = then_end = NULL; - if (else_last_head == else_end) - else_start = else_end = NULL; - - if (n_matching > 0) - { - if (then_start) - then_start = find_active_insn_after (then_bb, then_last_head); - if (else_start) - else_start = find_active_insn_after (else_bb, else_last_head); - n_insns -= 2 * n_matching; - } - } - } - - if (n_insns > max) - return FALSE; - - /* Map test_expr/test_jump into the appropriate MD tests to use on - the conditionally executed code. */ - - true_expr = test_expr; - - false_code = reversed_comparison_code (true_expr, BB_END (test_bb)); - if (false_code != UNKNOWN) - false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr), - XEXP (true_expr, 0), XEXP (true_expr, 1)); - else - false_expr = NULL_RTX; - -#ifdef IFCVT_MODIFY_TESTS - /* If the machine description needs to modify the tests, such as setting a - conditional execution register from a comparison, it can do so here. */ - IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr); - - /* See if the conversion failed. */ - if (!true_expr || !false_expr) - goto fail; -#endif - - note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX); - if (note) - { - true_prob_val = profile_probability::from_reg_br_prob_note (XINT (note, 0)); - false_prob_val = true_prob_val.invert (); - } - else - { - true_prob_val = profile_probability::uninitialized (); - false_prob_val = profile_probability::uninitialized (); - } - - /* If we have && or || tests, do them here. These tests are in the adjacent - blocks after the first block containing the test. */ - if (ce_info->num_multiple_test_blocks > 0) - { - basic_block bb = test_bb; - basic_block last_test_bb = ce_info->last_test_bb; - - if (! false_expr) - goto fail; - - do - { - rtx_insn *start, *end; - rtx t, f; - enum rtx_code f_code; - - bb = block_fallthru (bb); - start = first_active_insn (bb); - end = last_active_insn (bb, TRUE); - if (start - && ! cond_exec_process_insns (ce_info, start, end, false_expr, - false_prob_val, FALSE)) - goto fail; - - /* If the conditional jump is more than just a conditional jump, then - we cannot do conditional execution conversion on this block. */ - if (! onlyjump_p (BB_END (bb))) - goto fail; - - /* Find the conditional jump and isolate the test. */ - t = cond_exec_get_condition (BB_END (bb)); - if (! t) - goto fail; - - f_code = reversed_comparison_code (t, BB_END (bb)); - if (f_code == UNKNOWN) - goto fail; - - f = gen_rtx_fmt_ee (f_code, GET_MODE (t), XEXP (t, 0), XEXP (t, 1)); - if (ce_info->and_and_p) - { - t = gen_rtx_AND (GET_MODE (t), true_expr, t); - f = gen_rtx_IOR (GET_MODE (t), false_expr, f); - } - else - { - t = gen_rtx_IOR (GET_MODE (t), true_expr, t); - f = gen_rtx_AND (GET_MODE (t), false_expr, f); - } - - /* If the machine description needs to modify the tests, such as - setting a conditional execution register from a comparison, it can - do so here. */ -#ifdef IFCVT_MODIFY_MULTIPLE_TESTS - IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f); - - /* See if the conversion failed. */ - if (!t || !f) - goto fail; -#endif - - true_expr = t; - false_expr = f; - } - while (bb != last_test_bb); - } - - /* For IF-THEN-ELSE blocks, we don't allow modifications of the test - on then THEN block. */ - then_mod_ok = (else_bb == NULL_BLOCK); - - /* Go through the THEN and ELSE blocks converting the insns if possible - to conditional execution. */ - - if (then_end - && (! false_expr - || ! cond_exec_process_insns (ce_info, then_start, then_end, - false_expr, false_prob_val, - then_mod_ok))) - goto fail; - - if (else_bb && else_end - && ! cond_exec_process_insns (ce_info, else_start, else_end, - true_expr, true_prob_val, TRUE)) - goto fail; - - /* If we cannot apply the changes, fail. Do not go through the normal fail - processing, since apply_change_group will call cancel_changes. */ - if (! apply_change_group ()) - { -#ifdef IFCVT_MODIFY_CANCEL - /* Cancel any machine dependent changes. */ - IFCVT_MODIFY_CANCEL (ce_info); -#endif - return FALSE; - } - -#ifdef IFCVT_MODIFY_FINAL - /* Do any machine dependent final modifications. */ - IFCVT_MODIFY_FINAL (ce_info); -#endif - - /* Conversion succeeded. */ - if (dump_file) - fprintf (dump_file, "%d insn%s converted to conditional execution.\n", - n_insns, (n_insns == 1) ? " was" : "s were"); - - /* Merge the blocks! If we had matching sequences, make sure to delete one - copy at the appropriate location first: delete the copy in the THEN branch - for a tail sequence so that the remaining one is executed last for both - branches, and delete the copy in the ELSE branch for a head sequence so - that the remaining one is executed first for both branches. */ - if (then_first_tail) - { - rtx_insn *from = then_first_tail; - if (!INSN_P (from)) - from = find_active_insn_after (then_bb, from); - delete_insn_chain (from, get_last_bb_insn (then_bb), false); - } - if (else_last_head) - delete_insn_chain (first_active_insn (else_bb), else_last_head, false); - - merge_if_block (ce_info); - cond_exec_changed_p = TRUE; - return TRUE; - - fail: -#ifdef IFCVT_MODIFY_CANCEL - /* Cancel any machine dependent changes. */ - IFCVT_MODIFY_CANCEL (ce_info); -#endif - - cancel_changes (0); - return FALSE; -} - -static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int); -static int noce_try_move (struct noce_if_info *); -static int noce_try_ifelse_collapse (struct noce_if_info *); -static int noce_try_store_flag (struct noce_if_info *); -static int noce_try_addcc (struct noce_if_info *); -static int noce_try_store_flag_constants (struct noce_if_info *); -static int noce_try_store_flag_mask (struct noce_if_info *); -static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx, - rtx, rtx, rtx); -static int noce_try_cmove (struct noce_if_info *); -static int noce_try_cmove_arith (struct noce_if_info *); -static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **); -static int noce_try_minmax (struct noce_if_info *); -static int noce_try_abs (struct noce_if_info *); -static int noce_try_sign_mask (struct noce_if_info *); - -/* Return the comparison code for reversed condition for IF_INFO, - or UNKNOWN if reversing the condition is not possible. */ - -static inline enum rtx_code -noce_reversed_cond_code (struct noce_if_info *if_info) -{ - if (if_info->rev_cond) - return GET_CODE (if_info->rev_cond); - return reversed_comparison_code (if_info->cond, if_info->jump); -} - -/* Return true if SEQ is a good candidate as a replacement for the - if-convertible sequence described in IF_INFO. - This is the default implementation that targets can override - through a target hook. */ - -bool -default_noce_conversion_profitable_p (rtx_insn *seq, - struct noce_if_info *if_info) -{ - bool speed_p = if_info->speed_p; - - /* Cost up the new sequence. */ - unsigned int cost = seq_cost (seq, speed_p); - - if (cost <= if_info->original_cost) - return true; - - /* When compiling for size, we can make a reasonably accurately guess - at the size growth. When compiling for speed, use the maximum. */ - return speed_p && cost <= if_info->max_seq_cost; -} - -/* Helper function for noce_try_store_flag*. */ - -static rtx -noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep, - int normalize) -{ - rtx cond = if_info->cond; - int cond_complex; - enum rtx_code code; - - cond_complex = (! general_operand (XEXP (cond, 0), VOIDmode) - || ! general_operand (XEXP (cond, 1), VOIDmode)); - - /* If earliest == jump, or when the condition is complex, try to - build the store_flag insn directly. */ - - if (cond_complex) - { - rtx set = pc_set (if_info->jump); - cond = XEXP (SET_SRC (set), 0); - if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF - && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump)) - reversep = !reversep; - if (if_info->then_else_reversed) - reversep = !reversep; - } - else if (reversep - && if_info->rev_cond - && general_operand (XEXP (if_info->rev_cond, 0), VOIDmode) - && general_operand (XEXP (if_info->rev_cond, 1), VOIDmode)) - { - cond = if_info->rev_cond; - reversep = false; - } - - if (reversep) - code = reversed_comparison_code (cond, if_info->jump); - else - code = GET_CODE (cond); - - if ((if_info->cond_earliest == if_info->jump || cond_complex) - && (normalize == 0 || STORE_FLAG_VALUE == normalize)) - { - rtx src = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0), - XEXP (cond, 1)); - rtx set = gen_rtx_SET (x, src); - - start_sequence (); - rtx_insn *insn = emit_insn (set); - - if (recog_memoized (insn) >= 0) - { - rtx_insn *seq = get_insns (); - end_sequence (); - emit_insn (seq); - - if_info->cond_earliest = if_info->jump; - - return x; - } - - end_sequence (); - } - - /* Don't even try if the comparison operands or the mode of X are weird. */ - if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x))) - return NULL_RTX; - - return emit_store_flag (x, code, XEXP (cond, 0), - XEXP (cond, 1), VOIDmode, - (code == LTU || code == LEU - || code == GEU || code == GTU), normalize); -} - -/* Return true if X can be safely forced into a register by copy_to_mode_reg - / force_operand. */ - -static bool -noce_can_force_operand (rtx x) -{ - if (general_operand (x, VOIDmode)) - return true; - if (SUBREG_P (x)) - { - if (!noce_can_force_operand (SUBREG_REG (x))) - return false; - return true; - } - if (ARITHMETIC_P (x)) - { - if (!noce_can_force_operand (XEXP (x, 0)) - || !noce_can_force_operand (XEXP (x, 1))) - return false; - switch (GET_CODE (x)) - { - case MULT: - case DIV: - case MOD: - case UDIV: - case UMOD: - return true; - default: - return code_to_optab (GET_CODE (x)); - } - } - if (UNARY_P (x)) - { - if (!noce_can_force_operand (XEXP (x, 0))) - return false; - switch (GET_CODE (x)) - { - case ZERO_EXTEND: - case SIGN_EXTEND: - case TRUNCATE: - case FLOAT_EXTEND: - case FLOAT_TRUNCATE: - case FIX: - case UNSIGNED_FIX: - case FLOAT: - case UNSIGNED_FLOAT: - return true; - default: - return code_to_optab (GET_CODE (x)); - } - } - return false; -} - -/* Emit instruction to move an rtx, possibly into STRICT_LOW_PART. - X is the destination/target and Y is the value to copy. */ - -static void -noce_emit_move_insn (rtx x, rtx y) -{ - machine_mode outmode; - rtx outer, inner; - poly_int64 bitpos; - - if (GET_CODE (x) != STRICT_LOW_PART) - { - rtx_insn *seq, *insn; - rtx target; - optab ot; - - start_sequence (); - /* Check that the SET_SRC is reasonable before calling emit_move_insn, - otherwise construct a suitable SET pattern ourselves. */ - insn = (OBJECT_P (y) || CONSTANT_P (y) || GET_CODE (y) == SUBREG) - ? emit_move_insn (x, y) - : emit_insn (gen_rtx_SET (x, y)); - seq = get_insns (); - end_sequence (); - - if (recog_memoized (insn) <= 0) - { - if (GET_CODE (x) == ZERO_EXTRACT) - { - rtx op = XEXP (x, 0); - unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1)); - unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2)); - - /* store_bit_field expects START to be relative to - BYTES_BIG_ENDIAN and adjusts this value for machines with - BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN. In order to be able to - invoke store_bit_field again it is necessary to have the START - value from the first call. */ - if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN) - { - if (MEM_P (op)) - start = BITS_PER_UNIT - start - size; - else - { - gcc_assert (REG_P (op)); - start = BITS_PER_WORD - start - size; - } - } - - gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD)); - store_bit_field (op, size, start, 0, 0, GET_MODE (x), y, false); - return; - } - - switch (GET_RTX_CLASS (GET_CODE (y))) - { - case RTX_UNARY: - ot = code_to_optab (GET_CODE (y)); - if (ot && noce_can_force_operand (XEXP (y, 0))) - { - start_sequence (); - target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0); - if (target != NULL_RTX) - { - if (target != x) - emit_move_insn (x, target); - seq = get_insns (); - } - end_sequence (); - } - break; - - case RTX_BIN_ARITH: - case RTX_COMM_ARITH: - ot = code_to_optab (GET_CODE (y)); - if (ot - && noce_can_force_operand (XEXP (y, 0)) - && noce_can_force_operand (XEXP (y, 1))) - { - start_sequence (); - target = expand_binop (GET_MODE (y), ot, - XEXP (y, 0), XEXP (y, 1), - x, 0, OPTAB_DIRECT); - if (target != NULL_RTX) - { - if (target != x) - emit_move_insn (x, target); - seq = get_insns (); - } - end_sequence (); - } - break; - - default: - break; - } - } - - emit_insn (seq); - return; - } - - outer = XEXP (x, 0); - inner = XEXP (outer, 0); - outmode = GET_MODE (outer); - bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT; - store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, - 0, 0, outmode, y, false); -} - -/* Return the CC reg if it is used in COND. */ - -static rtx -cc_in_cond (rtx cond) -{ - if (have_cbranchcc4 && cond - && GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_CC) - return XEXP (cond, 0); - - return NULL_RTX; -} - -/* Return sequence of instructions generated by if conversion. This - function calls end_sequence() to end the current stream, ensures - that the instructions are unshared, recognizable non-jump insns. - On failure, this function returns a NULL_RTX. */ - -static rtx_insn * -end_ifcvt_sequence (struct noce_if_info *if_info) -{ - rtx_insn *insn; - rtx_insn *seq = get_insns (); - rtx cc = cc_in_cond (if_info->cond); - - set_used_flags (if_info->x); - set_used_flags (if_info->cond); - set_used_flags (if_info->a); - set_used_flags (if_info->b); - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - set_used_flags (insn); - - unshare_all_rtl_in_chain (seq); - end_sequence (); - - /* Make sure that all of the instructions emitted are recognizable, - and that we haven't introduced a new jump instruction. - As an exercise for the reader, build a general mechanism that - allows proper placement of required clobbers. */ - for (insn = seq; insn; insn = NEXT_INSN (insn)) - if (JUMP_P (insn) - || recog_memoized (insn) == -1 - /* Make sure new generated code does not clobber CC. */ - || (cc && set_of (cc, insn))) - return NULL; - - return seq; -} - -/* Return true iff the then and else basic block (if it exists) - consist of a single simple set instruction. */ - -static bool -noce_simple_bbs (struct noce_if_info *if_info) -{ - if (!if_info->then_simple) - return false; - - if (if_info->else_bb) - return if_info->else_simple; - - return true; -} - -/* Convert "if (a != b) x = a; else x = b" into "x = a" and - "if (a == b) x = a; else x = b" into "x = b". */ - -static int -noce_try_move (struct noce_if_info *if_info) -{ - rtx cond = if_info->cond; - enum rtx_code code = GET_CODE (cond); - rtx y; - rtx_insn *seq; - - if (code != NE && code != EQ) - return FALSE; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - /* This optimization isn't valid if either A or B could be a NaN - or a signed zero. */ - if (HONOR_NANS (if_info->x) - || HONOR_SIGNED_ZEROS (if_info->x)) - return FALSE; - - /* Check whether the operands of the comparison are A and in - either order. */ - if ((rtx_equal_p (if_info->a, XEXP (cond, 0)) - && rtx_equal_p (if_info->b, XEXP (cond, 1))) - || (rtx_equal_p (if_info->a, XEXP (cond, 1)) - && rtx_equal_p (if_info->b, XEXP (cond, 0)))) - { - if (!rtx_interchangeable_p (if_info->a, if_info->b)) - return FALSE; - - y = (code == EQ) ? if_info->a : if_info->b; - - /* Avoid generating the move if the source is the destination. */ - if (! rtx_equal_p (if_info->x, y)) - { - start_sequence (); - noce_emit_move_insn (if_info->x, y); - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - } - if_info->transform_name = "noce_try_move"; - return TRUE; - } - return FALSE; -} - -/* Try forming an IF_THEN_ELSE (cond, b, a) and collapsing that - through simplify_rtx. Sometimes that can eliminate the IF_THEN_ELSE. - If that is the case, emit the result into x. */ - -static int -noce_try_ifelse_collapse (struct noce_if_info * if_info) -{ - if (!noce_simple_bbs (if_info)) - return FALSE; - - machine_mode mode = GET_MODE (if_info->x); - rtx if_then_else = simplify_gen_ternary (IF_THEN_ELSE, mode, mode, - if_info->cond, if_info->b, - if_info->a); - - if (GET_CODE (if_then_else) == IF_THEN_ELSE) - return FALSE; - - rtx_insn *seq; - start_sequence (); - noce_emit_move_insn (if_info->x, if_then_else); - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - - if_info->transform_name = "noce_try_ifelse_collapse"; - return TRUE; -} - - -/* Convert "if (test) x = 1; else x = 0". - - Only try 0 and STORE_FLAG_VALUE here. Other combinations will be - tried in noce_try_store_flag_constants after noce_try_cmove has had - a go at the conversion. */ - -static int -noce_try_store_flag (struct noce_if_info *if_info) -{ - int reversep; - rtx target; - rtx_insn *seq; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - if (CONST_INT_P (if_info->b) - && INTVAL (if_info->b) == STORE_FLAG_VALUE - && if_info->a == const0_rtx) - reversep = 0; - else if (if_info->b == const0_rtx - && CONST_INT_P (if_info->a) - && INTVAL (if_info->a) == STORE_FLAG_VALUE - && noce_reversed_cond_code (if_info) != UNKNOWN) - reversep = 1; - else - return FALSE; - - start_sequence (); - - target = noce_emit_store_flag (if_info, if_info->x, reversep, 0); - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (! seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_store_flag"; - return TRUE; - } - else - { - end_sequence (); - return FALSE; - } -} - - -/* Convert "if (test) x = -A; else x = A" into - x = A; if (test) x = -x if the machine can do the - conditional negate form of this cheaply. - Try this before noce_try_cmove that will just load the - immediates into two registers and do a conditional select - between them. If the target has a conditional negate or - conditional invert operation we can save a potentially - expensive constant synthesis. */ - -static bool -noce_try_inverse_constants (struct noce_if_info *if_info) -{ - if (!noce_simple_bbs (if_info)) - return false; - - if (!CONST_INT_P (if_info->a) - || !CONST_INT_P (if_info->b) - || !REG_P (if_info->x)) - return false; - - machine_mode mode = GET_MODE (if_info->x); - - HOST_WIDE_INT val_a = INTVAL (if_info->a); - HOST_WIDE_INT val_b = INTVAL (if_info->b); - - rtx cond = if_info->cond; - - rtx x = if_info->x; - rtx target; - - start_sequence (); - - rtx_code code; - if (val_b != HOST_WIDE_INT_MIN && val_a == -val_b) - code = NEG; - else if (val_a == ~val_b) - code = NOT; - else - { - end_sequence (); - return false; - } - - rtx tmp = gen_reg_rtx (mode); - noce_emit_move_insn (tmp, if_info->a); - - target = emit_conditional_neg_or_complement (x, code, mode, cond, tmp, tmp); - - if (target) - { - rtx_insn *seq = get_insns (); - - if (!seq) - { - end_sequence (); - return false; - } - - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - - if (!seq) - return false; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_inverse_constants"; - return true; - } - - end_sequence (); - return false; -} - - -/* Convert "if (test) x = a; else x = b", for A and B constant. - Also allow A = y + c1, B = y + c2, with a common y between A - and B. */ - -static int -noce_try_store_flag_constants (struct noce_if_info *if_info) -{ - rtx target; - rtx_insn *seq; - bool reversep; - HOST_WIDE_INT itrue, ifalse, diff, tmp; - int normalize; - bool can_reverse; - machine_mode mode = GET_MODE (if_info->x); - rtx common = NULL_RTX; - - rtx a = if_info->a; - rtx b = if_info->b; - - /* Handle cases like x := test ? y + 3 : y + 4. */ - if (GET_CODE (a) == PLUS - && GET_CODE (b) == PLUS - && CONST_INT_P (XEXP (a, 1)) - && CONST_INT_P (XEXP (b, 1)) - && rtx_equal_p (XEXP (a, 0), XEXP (b, 0)) - /* Allow expressions that are not using the result or plain - registers where we handle overlap below. */ - && (REG_P (XEXP (a, 0)) - || (noce_operand_ok (XEXP (a, 0)) - && ! reg_overlap_mentioned_p (if_info->x, XEXP (a, 0))))) - { - common = XEXP (a, 0); - a = XEXP (a, 1); - b = XEXP (b, 1); - } - - if (!noce_simple_bbs (if_info)) - return FALSE; - - if (CONST_INT_P (a) - && CONST_INT_P (b)) - { - ifalse = INTVAL (a); - itrue = INTVAL (b); - bool subtract_flag_p = false; - - diff = (unsigned HOST_WIDE_INT) itrue - ifalse; - /* Make sure we can represent the difference between the two values. */ - if ((diff > 0) - != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue)) - return FALSE; - - diff = trunc_int_for_mode (diff, mode); - - can_reverse = noce_reversed_cond_code (if_info) != UNKNOWN; - reversep = false; - if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE) - { - normalize = 0; - /* We could collapse these cases but it is easier to follow the - diff/STORE_FLAG_VALUE combinations when they are listed - explicitly. */ - - /* test ? 3 : 4 - => 4 + (test != 0). */ - if (diff < 0 && STORE_FLAG_VALUE < 0) - reversep = false; - /* test ? 4 : 3 - => can_reverse | 4 + (test == 0) - !can_reverse | 3 - (test != 0). */ - else if (diff > 0 && STORE_FLAG_VALUE < 0) - { - reversep = can_reverse; - subtract_flag_p = !can_reverse; - /* If we need to subtract the flag and we have PLUS-immediate - A and B then it is unlikely to be beneficial to play tricks - here. */ - if (subtract_flag_p && common) - return FALSE; - } - /* test ? 3 : 4 - => can_reverse | 3 + (test == 0) - !can_reverse | 4 - (test != 0). */ - else if (diff < 0 && STORE_FLAG_VALUE > 0) - { - reversep = can_reverse; - subtract_flag_p = !can_reverse; - /* If we need to subtract the flag and we have PLUS-immediate - A and B then it is unlikely to be beneficial to play tricks - here. */ - if (subtract_flag_p && common) - return FALSE; - } - /* test ? 4 : 3 - => 4 + (test != 0). */ - else if (diff > 0 && STORE_FLAG_VALUE > 0) - reversep = false; - else - gcc_unreachable (); - } - /* Is this (cond) ? 2^n : 0? */ - else if (ifalse == 0 && pow2p_hwi (itrue) - && STORE_FLAG_VALUE == 1) - normalize = 1; - /* Is this (cond) ? 0 : 2^n? */ - else if (itrue == 0 && pow2p_hwi (ifalse) && can_reverse - && STORE_FLAG_VALUE == 1) - { - normalize = 1; - reversep = true; - } - /* Is this (cond) ? -1 : x? */ - else if (itrue == -1 - && STORE_FLAG_VALUE == -1) - normalize = -1; - /* Is this (cond) ? x : -1? */ - else if (ifalse == -1 && can_reverse - && STORE_FLAG_VALUE == -1) - { - normalize = -1; - reversep = true; - } - else - return FALSE; - - if (reversep) - { - std::swap (itrue, ifalse); - diff = trunc_int_for_mode (-(unsigned HOST_WIDE_INT) diff, mode); - } - - start_sequence (); - - /* If we have x := test ? x + 3 : x + 4 then move the original - x out of the way while we store flags. */ - if (common && rtx_equal_p (common, if_info->x)) - { - common = gen_reg_rtx (mode); - noce_emit_move_insn (common, if_info->x); - } - - target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize); - if (! target) - { - end_sequence (); - return FALSE; - } - - /* if (test) x = 3; else x = 4; - => x = 3 + (test == 0); */ - if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE) - { - /* Add the common part now. This may allow combine to merge this - with the store flag operation earlier into some sort of conditional - increment/decrement if the target allows it. */ - if (common) - target = expand_simple_binop (mode, PLUS, - target, common, - target, 0, OPTAB_WIDEN); - - /* Always use ifalse here. It should have been swapped with itrue - when appropriate when reversep is true. */ - target = expand_simple_binop (mode, subtract_flag_p ? MINUS : PLUS, - gen_int_mode (ifalse, mode), target, - if_info->x, 0, OPTAB_WIDEN); - } - /* Other cases are not beneficial when the original A and B are PLUS - expressions. */ - else if (common) - { - end_sequence (); - return FALSE; - } - /* if (test) x = 8; else x = 0; - => x = (test != 0) << 3; */ - else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0) - { - target = expand_simple_binop (mode, ASHIFT, - target, GEN_INT (tmp), if_info->x, 0, - OPTAB_WIDEN); - } - - /* if (test) x = -1; else x = b; - => x = -(test != 0) | b; */ - else if (itrue == -1) - { - target = expand_simple_binop (mode, IOR, - target, gen_int_mode (ifalse, mode), - if_info->x, 0, OPTAB_WIDEN); - } - else - { - end_sequence (); - return FALSE; - } - - if (! target) - { - end_sequence (); - return FALSE; - } - - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_store_flag_constants"; - - return TRUE; - } - - return FALSE; -} - -/* Convert "if (test) foo++" into "foo += (test != 0)", and - similarly for "foo--". */ - -static int -noce_try_addcc (struct noce_if_info *if_info) -{ - rtx target; - rtx_insn *seq; - int subtract, normalize; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - if (GET_CODE (if_info->a) == PLUS - && rtx_equal_p (XEXP (if_info->a, 0), if_info->b) - && noce_reversed_cond_code (if_info) != UNKNOWN) - { - rtx cond = if_info->rev_cond; - enum rtx_code code; - - if (cond == NULL_RTX) - { - cond = if_info->cond; - code = reversed_comparison_code (cond, if_info->jump); - } - else - code = GET_CODE (cond); - - /* First try to use addcc pattern. */ - if (general_operand (XEXP (cond, 0), VOIDmode) - && general_operand (XEXP (cond, 1), VOIDmode)) - { - start_sequence (); - target = emit_conditional_add (if_info->x, code, - XEXP (cond, 0), - XEXP (cond, 1), - VOIDmode, - if_info->b, - XEXP (if_info->a, 1), - GET_MODE (if_info->x), - (code == LTU || code == GEU - || code == LEU || code == GTU)); - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_addcc"; - - return TRUE; - } - end_sequence (); - } - - /* If that fails, construct conditional increment or decrement using - setcc. We're changing a branch and an increment to a comparison and - an ADD/SUB. */ - if (XEXP (if_info->a, 1) == const1_rtx - || XEXP (if_info->a, 1) == constm1_rtx) - { - start_sequence (); - if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1))) - subtract = 0, normalize = 0; - else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1))) - subtract = 1, normalize = 0; - else - subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1)); - - - target = noce_emit_store_flag (if_info, - gen_reg_rtx (GET_MODE (if_info->x)), - 1, normalize); - - if (target) - target = expand_simple_binop (GET_MODE (if_info->x), - subtract ? MINUS : PLUS, - if_info->b, target, if_info->x, - 0, OPTAB_WIDEN); - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_addcc"; - return TRUE; - } - end_sequence (); - } - } - - return FALSE; -} - -/* Convert "if (test) x = 0;" to "x &= -(test == 0);" */ - -static int -noce_try_store_flag_mask (struct noce_if_info *if_info) -{ - rtx target; - rtx_insn *seq; - int reversep; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - reversep = 0; - - if ((if_info->a == const0_rtx - && rtx_equal_p (if_info->b, if_info->x)) - || ((reversep = (noce_reversed_cond_code (if_info) != UNKNOWN)) - && if_info->b == const0_rtx - && rtx_equal_p (if_info->a, if_info->x))) - { - start_sequence (); - target = noce_emit_store_flag (if_info, - gen_reg_rtx (GET_MODE (if_info->x)), - reversep, -1); - if (target) - target = expand_simple_binop (GET_MODE (if_info->x), AND, - if_info->x, - target, if_info->x, 0, - OPTAB_WIDEN); - - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_store_flag_mask"; - - return TRUE; - } - - end_sequence (); - } - - return FALSE; -} - -/* Helper function for noce_try_cmove and noce_try_cmove_arith. */ - -static rtx -noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, - rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue) -{ - rtx target ATTRIBUTE_UNUSED; - int unsignedp ATTRIBUTE_UNUSED; - - /* If earliest == jump, try to build the cmove insn directly. - This is helpful when combine has created some complex condition - (like for alpha's cmovlbs) that we can't hope to regenerate - through the normal interface. */ - - if (if_info->cond_earliest == if_info->jump) - { - rtx cond = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b); - rtx if_then_else = gen_rtx_IF_THEN_ELSE (GET_MODE (x), - cond, vtrue, vfalse); - rtx set = gen_rtx_SET (x, if_then_else); - - start_sequence (); - rtx_insn *insn = emit_insn (set); - - if (recog_memoized (insn) >= 0) - { - rtx_insn *seq = get_insns (); - end_sequence (); - emit_insn (seq); - - return x; - } - - end_sequence (); - } - - /* Don't even try if the comparison operands are weird - except that the target supports cbranchcc4. */ - if (! general_operand (cmp_a, GET_MODE (cmp_a)) - || ! general_operand (cmp_b, GET_MODE (cmp_b))) - { - if (!have_cbranchcc4 - || GET_MODE_CLASS (GET_MODE (cmp_a)) != MODE_CC - || cmp_b != const0_rtx) - return NULL_RTX; - } - - unsignedp = (code == LTU || code == GEU - || code == LEU || code == GTU); - - target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode, - vtrue, vfalse, GET_MODE (x), - unsignedp); - if (target) - return target; - - /* We might be faced with a situation like: - - x = (reg:M TARGET) - vtrue = (subreg:M (reg:N VTRUE) BYTE) - vfalse = (subreg:M (reg:N VFALSE) BYTE) - - We can't do a conditional move in mode M, but it's possible that we - could do a conditional move in mode N instead and take a subreg of - the result. - - If we can't create new pseudos, though, don't bother. */ - if (reload_completed) - return NULL_RTX; - - if (GET_CODE (vtrue) == SUBREG && GET_CODE (vfalse) == SUBREG) - { - rtx reg_vtrue = SUBREG_REG (vtrue); - rtx reg_vfalse = SUBREG_REG (vfalse); - poly_uint64 byte_vtrue = SUBREG_BYTE (vtrue); - poly_uint64 byte_vfalse = SUBREG_BYTE (vfalse); - rtx promoted_target; - - if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse) - || maybe_ne (byte_vtrue, byte_vfalse) - || (SUBREG_PROMOTED_VAR_P (vtrue) - != SUBREG_PROMOTED_VAR_P (vfalse)) - || (SUBREG_PROMOTED_GET (vtrue) - != SUBREG_PROMOTED_GET (vfalse))) - return NULL_RTX; - - promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue)); - - target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b, - VOIDmode, reg_vtrue, reg_vfalse, - GET_MODE (reg_vtrue), unsignedp); - /* Nope, couldn't do it in that mode either. */ - if (!target) - return NULL_RTX; - - target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue); - SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue); - SUBREG_PROMOTED_SET (target, SUBREG_PROMOTED_GET (vtrue)); - emit_move_insn (x, target); - return x; - } - else - return NULL_RTX; -} - -/* Try only simple constants and registers here. More complex cases - are handled in noce_try_cmove_arith after noce_try_store_flag_arith - has had a go at it. */ - -static int -noce_try_cmove (struct noce_if_info *if_info) -{ - enum rtx_code code; - rtx target; - rtx_insn *seq; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode)) - && (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode))) - { - start_sequence (); - - code = GET_CODE (if_info->cond); - target = noce_emit_cmove (if_info, if_info->x, code, - XEXP (if_info->cond, 0), - XEXP (if_info->cond, 1), - if_info->a, if_info->b); - - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_cmove"; - - return TRUE; - } - /* If both a and b are constants try a last-ditch transformation: - if (test) x = a; else x = b; - => x = (-(test != 0) & (b - a)) + a; - Try this only if the target-specific expansion above has failed. - The target-specific expander may want to generate sequences that - we don't know about, so give them a chance before trying this - approach. */ - else if (!targetm.have_conditional_execution () - && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b)) - { - machine_mode mode = GET_MODE (if_info->x); - HOST_WIDE_INT ifalse = INTVAL (if_info->a); - HOST_WIDE_INT itrue = INTVAL (if_info->b); - rtx target = noce_emit_store_flag (if_info, if_info->x, false, -1); - if (!target) - { - end_sequence (); - return FALSE; - } - - HOST_WIDE_INT diff = (unsigned HOST_WIDE_INT) itrue - ifalse; - /* Make sure we can represent the difference - between the two values. */ - if ((diff > 0) - != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue)) - { - end_sequence (); - return FALSE; - } - - diff = trunc_int_for_mode (diff, mode); - target = expand_simple_binop (mode, AND, - target, gen_int_mode (diff, mode), - if_info->x, 0, OPTAB_WIDEN); - if (target) - target = expand_simple_binop (mode, PLUS, - target, gen_int_mode (ifalse, mode), - if_info->x, 0, OPTAB_WIDEN); - if (target) - { - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info)) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_cmove"; - return TRUE; - } - else - { - end_sequence (); - return FALSE; - } - } - else - end_sequence (); - } - - return FALSE; -} - -/* Return true if X contains a conditional code mode rtx. */ - -static bool -contains_ccmode_rtx_p (rtx x) -{ - subrtx_iterator::array_type array; - FOR_EACH_SUBRTX (iter, array, x, ALL) - if (GET_MODE_CLASS (GET_MODE (*iter)) == MODE_CC) - return true; - - return false; -} - -/* Helper for bb_valid_for_noce_process_p. Validate that - the rtx insn INSN is a single set that does not set - the conditional register CC and is in general valid for - if-conversion. */ - -static bool -insn_valid_noce_process_p (rtx_insn *insn, rtx cc) -{ - if (!insn - || !NONJUMP_INSN_P (insn) - || (cc && set_of (cc, insn))) - return false; - - rtx sset = single_set (insn); - - /* Currently support only simple single sets in test_bb. */ - if (!sset - || !noce_operand_ok (SET_DEST (sset)) - || contains_ccmode_rtx_p (SET_DEST (sset)) - || !noce_operand_ok (SET_SRC (sset))) - return false; - - return true; -} - - -/* Return true iff the registers that the insns in BB_A set do not get - used in BB_B. If TO_RENAME is non-NULL then it is a location that will be - renamed later by the caller and so conflicts on it should be ignored - in this function. */ - -static bool -bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b, rtx to_rename) -{ - rtx_insn *a_insn; - bitmap bba_sets = BITMAP_ALLOC (®_obstack); - - df_ref def; - df_ref use; - - FOR_BB_INSNS (bb_a, a_insn) - { - if (!active_insn_p (a_insn)) - continue; - - rtx sset_a = single_set (a_insn); - - if (!sset_a) - { - BITMAP_FREE (bba_sets); - return false; - } - /* Record all registers that BB_A sets. */ - FOR_EACH_INSN_DEF (def, a_insn) - if (!(to_rename && DF_REF_REG (def) == to_rename)) - bitmap_set_bit (bba_sets, DF_REF_REGNO (def)); - } - - rtx_insn *b_insn; - - FOR_BB_INSNS (bb_b, b_insn) - { - if (!active_insn_p (b_insn)) - continue; - - rtx sset_b = single_set (b_insn); - - if (!sset_b) - { - BITMAP_FREE (bba_sets); - return false; - } - - /* Make sure this is a REG and not some instance - of ZERO_EXTRACT or SUBREG or other dangerous stuff. - If we have a memory destination then we have a pair of simple - basic blocks performing an operation of the form [addr] = c ? a : b. - bb_valid_for_noce_process_p will have ensured that these are - the only stores present. In that case [addr] should be the location - to be renamed. Assert that the callers set this up properly. */ - if (MEM_P (SET_DEST (sset_b))) - gcc_assert (rtx_equal_p (SET_DEST (sset_b), to_rename)); - else if (!REG_P (SET_DEST (sset_b))) - { - BITMAP_FREE (bba_sets); - return false; - } - - /* If the insn uses a reg set in BB_A return false. */ - FOR_EACH_INSN_USE (use, b_insn) - { - if (bitmap_bit_p (bba_sets, DF_REF_REGNO (use))) - { - BITMAP_FREE (bba_sets); - return false; - } - } - - } - - BITMAP_FREE (bba_sets); - return true; -} - -/* Emit copies of all the active instructions in BB except the last. - This is a helper for noce_try_cmove_arith. */ - -static void -noce_emit_all_but_last (basic_block bb) -{ - rtx_insn *last = last_active_insn (bb, FALSE); - rtx_insn *insn; - FOR_BB_INSNS (bb, insn) - { - if (insn != last && active_insn_p (insn)) - { - rtx_insn *to_emit = as_a <rtx_insn *> (copy_rtx (insn)); - - emit_insn (PATTERN (to_emit)); - } - } -} - -/* Helper for noce_try_cmove_arith. Emit the pattern TO_EMIT and return - the resulting insn or NULL if it's not a valid insn. */ - -static rtx_insn * -noce_emit_insn (rtx to_emit) -{ - gcc_assert (to_emit); - rtx_insn *insn = emit_insn (to_emit); - - if (recog_memoized (insn) < 0) - return NULL; - - return insn; -} - -/* Helper for noce_try_cmove_arith. Emit a copy of the insns up to - and including the penultimate one in BB if it is not simple - (as indicated by SIMPLE). Then emit LAST_INSN as the last - insn in the block. The reason for that is that LAST_INSN may - have been modified by the preparation in noce_try_cmove_arith. */ - -static bool -noce_emit_bb (rtx last_insn, basic_block bb, bool simple) -{ - if (bb && !simple) - noce_emit_all_but_last (bb); - - if (last_insn && !noce_emit_insn (last_insn)) - return false; - - return true; -} - -/* Try more complex cases involving conditional_move. */ - -static int -noce_try_cmove_arith (struct noce_if_info *if_info) -{ - rtx a = if_info->a; - rtx b = if_info->b; - rtx x = if_info->x; - rtx orig_a, orig_b; - rtx_insn *insn_a, *insn_b; - bool a_simple = if_info->then_simple; - bool b_simple = if_info->else_simple; - basic_block then_bb = if_info->then_bb; - basic_block else_bb = if_info->else_bb; - rtx target; - int is_mem = 0; - enum rtx_code code; - rtx cond = if_info->cond; - rtx_insn *ifcvt_seq; - - /* A conditional move from two memory sources is equivalent to a - conditional on their addresses followed by a load. Don't do this - early because it'll screw alias analysis. Note that we've - already checked for no side effects. */ - if (cse_not_expected - && MEM_P (a) && MEM_P (b) - && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b)) - { - machine_mode address_mode = get_address_mode (a); - - a = XEXP (a, 0); - b = XEXP (b, 0); - x = gen_reg_rtx (address_mode); - is_mem = 1; - } - - /* ??? We could handle this if we knew that a load from A or B could - not trap or fault. This is also true if we've already loaded - from the address along the path from ENTRY. */ - else if (may_trap_or_fault_p (a) || may_trap_or_fault_p (b)) - return FALSE; - - /* if (test) x = a + b; else x = c - d; - => y = a + b; - x = c - d; - if (test) - x = y; - */ - - code = GET_CODE (cond); - insn_a = if_info->insn_a; - insn_b = if_info->insn_b; - - machine_mode x_mode = GET_MODE (x); - - if (!can_conditionally_move_p (x_mode)) - return FALSE; - - /* Possibly rearrange operands to make things come out more natural. */ - if (noce_reversed_cond_code (if_info) != UNKNOWN) - { - int reversep = 0; - if (rtx_equal_p (b, x)) - reversep = 1; - else if (general_operand (b, GET_MODE (b))) - reversep = 1; - - if (reversep) - { - if (if_info->rev_cond) - { - cond = if_info->rev_cond; - code = GET_CODE (cond); - } - else - code = reversed_comparison_code (cond, if_info->jump); - std::swap (a, b); - std::swap (insn_a, insn_b); - std::swap (a_simple, b_simple); - std::swap (then_bb, else_bb); - } - } - - if (then_bb && else_bb - && (!bbs_ok_for_cmove_arith (then_bb, else_bb, if_info->orig_x) - || !bbs_ok_for_cmove_arith (else_bb, then_bb, if_info->orig_x))) - return FALSE; - - start_sequence (); - - /* If one of the blocks is empty then the corresponding B or A value - came from the test block. The non-empty complex block that we will - emit might clobber the register used by B or A, so move it to a pseudo - first. */ - - rtx tmp_a = NULL_RTX; - rtx tmp_b = NULL_RTX; - - if (b_simple || !else_bb) - tmp_b = gen_reg_rtx (x_mode); - - if (a_simple || !then_bb) - tmp_a = gen_reg_rtx (x_mode); - - orig_a = a; - orig_b = b; - - rtx emit_a = NULL_RTX; - rtx emit_b = NULL_RTX; - rtx_insn *tmp_insn = NULL; - bool modified_in_a = false; - bool modified_in_b = false; - /* If either operand is complex, load it into a register first. - The best way to do this is to copy the original insn. In this - way we preserve any clobbers etc that the insn may have had. - This is of course not possible in the IS_MEM case. */ - - if (! general_operand (a, GET_MODE (a)) || tmp_a) - { - - if (is_mem) - { - rtx reg = gen_reg_rtx (GET_MODE (a)); - emit_a = gen_rtx_SET (reg, a); - } - else - { - if (insn_a) - { - a = tmp_a ? tmp_a : gen_reg_rtx (GET_MODE (a)); - - rtx_insn *copy_of_a = as_a <rtx_insn *> (copy_rtx (insn_a)); - rtx set = single_set (copy_of_a); - SET_DEST (set) = a; - - emit_a = PATTERN (copy_of_a); - } - else - { - rtx tmp_reg = tmp_a ? tmp_a : gen_reg_rtx (GET_MODE (a)); - emit_a = gen_rtx_SET (tmp_reg, a); - a = tmp_reg; - } - } - } - - if (! general_operand (b, GET_MODE (b)) || tmp_b) - { - if (is_mem) - { - rtx reg = gen_reg_rtx (GET_MODE (b)); - emit_b = gen_rtx_SET (reg, b); - } - else - { - if (insn_b) - { - b = tmp_b ? tmp_b : gen_reg_rtx (GET_MODE (b)); - rtx_insn *copy_of_b = as_a <rtx_insn *> (copy_rtx (insn_b)); - rtx set = single_set (copy_of_b); - - SET_DEST (set) = b; - emit_b = PATTERN (copy_of_b); - } - else - { - rtx tmp_reg = tmp_b ? tmp_b : gen_reg_rtx (GET_MODE (b)); - emit_b = gen_rtx_SET (tmp_reg, b); - b = tmp_reg; - } - } - } - - modified_in_a = emit_a != NULL_RTX && modified_in_p (orig_b, emit_a); - if (tmp_b && then_bb) - { - FOR_BB_INSNS (then_bb, tmp_insn) - /* Don't check inside insn_a. We will have changed it to emit_a - with a destination that doesn't conflict. */ - if (!(insn_a && tmp_insn == insn_a) - && modified_in_p (orig_b, tmp_insn)) - { - modified_in_a = true; - break; - } - - } - - modified_in_b = emit_b != NULL_RTX && modified_in_p (orig_a, emit_b); - if (tmp_a && else_bb) - { - FOR_BB_INSNS (else_bb, tmp_insn) - /* Don't check inside insn_b. We will have changed it to emit_b - with a destination that doesn't conflict. */ - if (!(insn_b && tmp_insn == insn_b) - && modified_in_p (orig_a, tmp_insn)) - { - modified_in_b = true; - break; - } - } - - /* If insn to set up A clobbers any registers B depends on, try to - swap insn that sets up A with the one that sets up B. If even - that doesn't help, punt. */ - if (modified_in_a && !modified_in_b) - { - if (!noce_emit_bb (emit_b, else_bb, b_simple)) - goto end_seq_and_fail; - - if (!noce_emit_bb (emit_a, then_bb, a_simple)) - goto end_seq_and_fail; - } - else if (!modified_in_a) - { - if (!noce_emit_bb (emit_a, then_bb, a_simple)) - goto end_seq_and_fail; - - if (!noce_emit_bb (emit_b, else_bb, b_simple)) - goto end_seq_and_fail; - } - else - goto end_seq_and_fail; - - target = noce_emit_cmove (if_info, x, code, XEXP (cond, 0), XEXP (cond, 1), - a, b); - - if (! target) - goto end_seq_and_fail; - - /* If we're handling a memory for above, emit the load now. */ - if (is_mem) - { - rtx mem = gen_rtx_MEM (GET_MODE (if_info->x), target); - - /* Copy over flags as appropriate. */ - if (MEM_VOLATILE_P (if_info->a) || MEM_VOLATILE_P (if_info->b)) - MEM_VOLATILE_P (mem) = 1; - if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b)) - set_mem_alias_set (mem, MEM_ALIAS_SET (if_info->a)); - set_mem_align (mem, - MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b))); - - gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b)); - set_mem_addr_space (mem, MEM_ADDR_SPACE (if_info->a)); - - noce_emit_move_insn (if_info->x, mem); - } - else if (target != x) - noce_emit_move_insn (x, target); - - ifcvt_seq = end_ifcvt_sequence (if_info); - if (!ifcvt_seq || !targetm.noce_conversion_profitable_p (ifcvt_seq, if_info)) - return FALSE; - - emit_insn_before_setloc (ifcvt_seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_cmove_arith"; - return TRUE; - - end_seq_and_fail: - end_sequence (); - return FALSE; -} - -/* For most cases, the simplified condition we found is the best - choice, but this is not the case for the min/max/abs transforms. - For these we wish to know that it is A or B in the condition. */ - -static rtx -noce_get_alt_condition (struct noce_if_info *if_info, rtx target, - rtx_insn **earliest) -{ - rtx cond, set; - rtx_insn *insn; - int reverse; - - /* If target is already mentioned in the known condition, return it. */ - if (reg_mentioned_p (target, if_info->cond)) - { - *earliest = if_info->cond_earliest; - return if_info->cond; - } - - set = pc_set (if_info->jump); - cond = XEXP (SET_SRC (set), 0); - reverse - = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF - && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump); - if (if_info->then_else_reversed) - reverse = !reverse; - - /* If we're looking for a constant, try to make the conditional - have that constant in it. There are two reasons why it may - not have the constant we want: - - 1. GCC may have needed to put the constant in a register, because - the target can't compare directly against that constant. For - this case, we look for a SET immediately before the comparison - that puts a constant in that register. - - 2. GCC may have canonicalized the conditional, for example - replacing "if x < 4" with "if x <= 3". We can undo that (or - make equivalent types of changes) to get the constants we need - if they're off by one in the right direction. */ - - if (CONST_INT_P (target)) - { - enum rtx_code code = GET_CODE (if_info->cond); - rtx op_a = XEXP (if_info->cond, 0); - rtx op_b = XEXP (if_info->cond, 1); - rtx_insn *prev_insn; - - /* First, look to see if we put a constant in a register. */ - prev_insn = prev_nonnote_nondebug_insn (if_info->cond_earliest); - if (prev_insn - && BLOCK_FOR_INSN (prev_insn) - == BLOCK_FOR_INSN (if_info->cond_earliest) - && INSN_P (prev_insn) - && GET_CODE (PATTERN (prev_insn)) == SET) - { - rtx src = find_reg_equal_equiv_note (prev_insn); - if (!src) - src = SET_SRC (PATTERN (prev_insn)); - if (CONST_INT_P (src)) - { - if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn)))) - op_a = src; - else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn)))) - op_b = src; - - if (CONST_INT_P (op_a)) - { - std::swap (op_a, op_b); - code = swap_condition (code); - } - } - } - - /* Now, look to see if we can get the right constant by - adjusting the conditional. */ - if (CONST_INT_P (op_b)) - { - HOST_WIDE_INT desired_val = INTVAL (target); - HOST_WIDE_INT actual_val = INTVAL (op_b); - - switch (code) - { - case LT: - if (desired_val != HOST_WIDE_INT_MAX - && actual_val == desired_val + 1) - { - code = LE; - op_b = GEN_INT (desired_val); - } - break; - case LE: - if (desired_val != HOST_WIDE_INT_MIN - && actual_val == desired_val - 1) - { - code = LT; - op_b = GEN_INT (desired_val); - } - break; - case GT: - if (desired_val != HOST_WIDE_INT_MIN - && actual_val == desired_val - 1) - { - code = GE; - op_b = GEN_INT (desired_val); - } - break; - case GE: - if (desired_val != HOST_WIDE_INT_MAX - && actual_val == desired_val + 1) - { - code = GT; - op_b = GEN_INT (desired_val); - } - break; - default: - break; - } - } - - /* If we made any changes, generate a new conditional that is - equivalent to what we started with, but has the right - constants in it. */ - if (code != GET_CODE (if_info->cond) - || op_a != XEXP (if_info->cond, 0) - || op_b != XEXP (if_info->cond, 1)) - { - cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b); - *earliest = if_info->cond_earliest; - return cond; - } - } - - cond = canonicalize_condition (if_info->jump, cond, reverse, - earliest, target, have_cbranchcc4, true); - if (! cond || ! reg_mentioned_p (target, cond)) - return NULL; - - /* We almost certainly searched back to a different place. - Need to re-verify correct lifetimes. */ - - /* X may not be mentioned in the range (cond_earliest, jump]. */ - for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn)) - if (INSN_P (insn) && reg_overlap_mentioned_p (if_info->x, PATTERN (insn))) - return NULL; - - /* A and B may not be modified in the range [cond_earliest, jump). */ - for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn)) - if (INSN_P (insn) - && (modified_in_p (if_info->a, insn) - || modified_in_p (if_info->b, insn))) - return NULL; - - return cond; -} - -/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */ - -static int -noce_try_minmax (struct noce_if_info *if_info) -{ - rtx cond, target; - rtx_insn *earliest, *seq; - enum rtx_code code, op; - int unsignedp; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - /* ??? Reject modes with NaNs or signed zeros since we don't know how - they will be resolved with an SMIN/SMAX. It wouldn't be too hard - to get the target to tell us... */ - if (HONOR_SIGNED_ZEROS (if_info->x) - || HONOR_NANS (if_info->x)) - return FALSE; - - cond = noce_get_alt_condition (if_info, if_info->a, &earliest); - if (!cond) - return FALSE; - - /* Verify the condition is of the form we expect, and canonicalize - the comparison code. */ - code = GET_CODE (cond); - if (rtx_equal_p (XEXP (cond, 0), if_info->a)) - { - if (! rtx_equal_p (XEXP (cond, 1), if_info->b)) - return FALSE; - } - else if (rtx_equal_p (XEXP (cond, 1), if_info->a)) - { - if (! rtx_equal_p (XEXP (cond, 0), if_info->b)) - return FALSE; - code = swap_condition (code); - } - else - return FALSE; - - /* Determine what sort of operation this is. Note that the code is for - a taken branch, so the code->operation mapping appears backwards. */ - switch (code) - { - case LT: - case LE: - case UNLT: - case UNLE: - op = SMAX; - unsignedp = 0; - break; - case GT: - case GE: - case UNGT: - case UNGE: - op = SMIN; - unsignedp = 0; - break; - case LTU: - case LEU: - op = UMAX; - unsignedp = 1; - break; - case GTU: - case GEU: - op = UMIN; - unsignedp = 1; - break; - default: - return FALSE; - } - - start_sequence (); - - target = expand_simple_binop (GET_MODE (if_info->x), op, - if_info->a, if_info->b, - if_info->x, unsignedp, OPTAB_WIDEN); - if (! target) - { - end_sequence (); - return FALSE; - } - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); - if_info->cond = cond; - if_info->cond_earliest = earliest; - if_info->rev_cond = NULL_RTX; - if_info->transform_name = "noce_try_minmax"; - - return TRUE; -} - -/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", - "if (a < 0) x = ~a; else x = a;" to "x = one_cmpl_abs(a);", - etc. */ - -static int -noce_try_abs (struct noce_if_info *if_info) -{ - rtx cond, target, a, b, c; - rtx_insn *earliest, *seq; - int negate; - bool one_cmpl = false; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - /* Reject modes with signed zeros. */ - if (HONOR_SIGNED_ZEROS (if_info->x)) - return FALSE; - - /* Recognize A and B as constituting an ABS or NABS. The canonical - form is a branch around the negation, taken when the object is the - first operand of a comparison against 0 that evaluates to true. */ - a = if_info->a; - b = if_info->b; - if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b)) - negate = 0; - else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a)) - { - std::swap (a, b); - negate = 1; - } - else if (GET_CODE (a) == NOT && rtx_equal_p (XEXP (a, 0), b)) - { - negate = 0; - one_cmpl = true; - } - else if (GET_CODE (b) == NOT && rtx_equal_p (XEXP (b, 0), a)) - { - std::swap (a, b); - negate = 1; - one_cmpl = true; - } - else - return FALSE; - - cond = noce_get_alt_condition (if_info, b, &earliest); - if (!cond) - return FALSE; - - /* Verify the condition is of the form we expect. */ - if (rtx_equal_p (XEXP (cond, 0), b)) - c = XEXP (cond, 1); - else if (rtx_equal_p (XEXP (cond, 1), b)) - { - c = XEXP (cond, 0); - negate = !negate; - } - else - return FALSE; - - /* Verify that C is zero. Search one step backward for a - REG_EQUAL note or a simple source if necessary. */ - if (REG_P (c)) - { - rtx set; - rtx_insn *insn = prev_nonnote_nondebug_insn (earliest); - if (insn - && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest) - && (set = single_set (insn)) - && rtx_equal_p (SET_DEST (set), c)) - { - rtx note = find_reg_equal_equiv_note (insn); - if (note) - c = XEXP (note, 0); - else - c = SET_SRC (set); - } - else - return FALSE; - } - if (MEM_P (c) - && GET_CODE (XEXP (c, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0))) - c = get_pool_constant (XEXP (c, 0)); - - /* Work around funny ideas get_condition has wrt canonicalization. - Note that these rtx constants are known to be CONST_INT, and - therefore imply integer comparisons. - The one_cmpl case is more complicated, as we want to handle - only x < 0 ? ~x : x or x >= 0 ? x : ~x to one_cmpl_abs (x) - and x < 0 ? x : ~x or x >= 0 ? ~x : x to ~one_cmpl_abs (x), - but not other cases (x > -1 is equivalent of x >= 0). */ - if (c == constm1_rtx && GET_CODE (cond) == GT) - ; - else if (c == const1_rtx && GET_CODE (cond) == LT) - { - if (one_cmpl) - return FALSE; - } - else if (c == CONST0_RTX (GET_MODE (b))) - { - if (one_cmpl - && GET_CODE (cond) != GE - && GET_CODE (cond) != LT) - return FALSE; - } - else - return FALSE; - - /* Determine what sort of operation this is. */ - switch (GET_CODE (cond)) - { - case LT: - case LE: - case UNLT: - case UNLE: - negate = !negate; - break; - case GT: - case GE: - case UNGT: - case UNGE: - break; - default: - return FALSE; - } - - start_sequence (); - if (one_cmpl) - target = expand_one_cmpl_abs_nojump (GET_MODE (if_info->x), b, - if_info->x); - else - target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1); - - /* ??? It's a quandary whether cmove would be better here, especially - for integers. Perhaps combine will clean things up. */ - if (target && negate) - { - if (one_cmpl) - target = expand_simple_unop (GET_MODE (target), NOT, target, - if_info->x, 0); - else - target = expand_simple_unop (GET_MODE (target), NEG, target, - if_info->x, 0); - } - - if (! target) - { - end_sequence (); - return FALSE; - } - - if (target != if_info->x) - noce_emit_move_insn (if_info->x, target); - - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); - if_info->cond = cond; - if_info->cond_earliest = earliest; - if_info->rev_cond = NULL_RTX; - if_info->transform_name = "noce_try_abs"; - - return TRUE; -} - -/* Convert "if (m < 0) x = b; else x = 0;" to "x = (m >> C) & b;". */ - -static int -noce_try_sign_mask (struct noce_if_info *if_info) -{ - rtx cond, t, m, c; - rtx_insn *seq; - machine_mode mode; - enum rtx_code code; - bool t_unconditional; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - cond = if_info->cond; - code = GET_CODE (cond); - m = XEXP (cond, 0); - c = XEXP (cond, 1); - - t = NULL_RTX; - if (if_info->a == const0_rtx) - { - if ((code == LT && c == const0_rtx) - || (code == LE && c == constm1_rtx)) - t = if_info->b; - } - else if (if_info->b == const0_rtx) - { - if ((code == GE && c == const0_rtx) - || (code == GT && c == constm1_rtx)) - t = if_info->a; - } - - if (! t || side_effects_p (t)) - return FALSE; - - /* We currently don't handle different modes. */ - mode = GET_MODE (t); - if (GET_MODE (m) != mode) - return FALSE; - - /* This is only profitable if T is unconditionally executed/evaluated in the - original insn sequence or T is cheap. The former happens if B is the - non-zero (T) value and if INSN_B was taken from TEST_BB, or there was no - INSN_B which can happen for e.g. conditional stores to memory. For the - cost computation use the block TEST_BB where the evaluation will end up - after the transformation. */ - t_unconditional - = (t == if_info->b - && (if_info->insn_b == NULL_RTX - || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb)); - if (!(t_unconditional - || (set_src_cost (t, mode, if_info->speed_p) - < COSTS_N_INSNS (2)))) - return FALSE; - - if (!noce_can_force_operand (t)) - return FALSE; - - start_sequence (); - /* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding - "(signed) m >> 31" directly. This benefits targets with specialized - insns to obtain the signmask, but still uses ashr_optab otherwise. */ - m = emit_store_flag (gen_reg_rtx (mode), LT, m, const0_rtx, mode, 0, -1); - t = m ? expand_binop (mode, and_optab, m, t, NULL_RTX, 0, OPTAB_DIRECT) - : NULL_RTX; - - if (!t) - { - end_sequence (); - return FALSE; - } - - noce_emit_move_insn (if_info->x, t); - - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); - if_info->transform_name = "noce_try_sign_mask"; - - return TRUE; -} - - -/* Optimize away "if (x & C) x |= C" and similar bit manipulation - transformations. */ - -static int -noce_try_bitop (struct noce_if_info *if_info) -{ - rtx cond, x, a, result; - rtx_insn *seq; - scalar_int_mode mode; - enum rtx_code code; - int bitnum; - - x = if_info->x; - cond = if_info->cond; - code = GET_CODE (cond); - - /* Check for an integer operation. */ - if (!is_a <scalar_int_mode> (GET_MODE (x), &mode)) - return FALSE; - - if (!noce_simple_bbs (if_info)) - return FALSE; - - /* Check for no else condition. */ - if (! rtx_equal_p (x, if_info->b)) - return FALSE; - - /* Check for a suitable condition. */ - if (code != NE && code != EQ) - return FALSE; - if (XEXP (cond, 1) != const0_rtx) - return FALSE; - cond = XEXP (cond, 0); - - /* ??? We could also handle AND here. */ - if (GET_CODE (cond) == ZERO_EXTRACT) - { - if (XEXP (cond, 1) != const1_rtx - || !CONST_INT_P (XEXP (cond, 2)) - || ! rtx_equal_p (x, XEXP (cond, 0))) - return FALSE; - bitnum = INTVAL (XEXP (cond, 2)); - if (BITS_BIG_ENDIAN) - bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum; - if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT) - return FALSE; - } - else - return FALSE; - - a = if_info->a; - if (GET_CODE (a) == IOR || GET_CODE (a) == XOR) - { - /* Check for "if (X & C) x = x op C". */ - if (! rtx_equal_p (x, XEXP (a, 0)) - || !CONST_INT_P (XEXP (a, 1)) - || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode)) - != HOST_WIDE_INT_1U << bitnum) - return FALSE; - - /* if ((x & C) == 0) x |= C; is transformed to x |= C. */ - /* if ((x & C) != 0) x |= C; is transformed to nothing. */ - if (GET_CODE (a) == IOR) - result = (code == NE) ? a : NULL_RTX; - else if (code == NE) - { - /* if ((x & C) == 0) x ^= C; is transformed to x |= C. */ - result = gen_int_mode (HOST_WIDE_INT_1 << bitnum, mode); - result = simplify_gen_binary (IOR, mode, x, result); - } - else - { - /* if ((x & C) != 0) x ^= C; is transformed to x &= ~C. */ - result = gen_int_mode (~(HOST_WIDE_INT_1 << bitnum), mode); - result = simplify_gen_binary (AND, mode, x, result); - } - } - else if (GET_CODE (a) == AND) - { - /* Check for "if (X & C) x &= ~C". */ - if (! rtx_equal_p (x, XEXP (a, 0)) - || !CONST_INT_P (XEXP (a, 1)) - || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode)) - != (~(HOST_WIDE_INT_1 << bitnum) & GET_MODE_MASK (mode))) - return FALSE; - - /* if ((x & C) == 0) x &= ~C; is transformed to nothing. */ - /* if ((x & C) != 0) x &= ~C; is transformed to x &= ~C. */ - result = (code == EQ) ? a : NULL_RTX; - } - else - return FALSE; - - if (result) - { - start_sequence (); - noce_emit_move_insn (x, result); - seq = end_ifcvt_sequence (if_info); - if (!seq) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (if_info->insn_a)); - } - if_info->transform_name = "noce_try_bitop"; - return TRUE; -} - - -/* Similar to get_condition, only the resulting condition must be - valid at JUMP, instead of at EARLIEST. - - If THEN_ELSE_REVERSED is true, the fallthrough does not go to the - THEN block of the caller, and we have to reverse the condition. */ - -static rtx -noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed) -{ - rtx cond, set, tmp; - bool reverse; - - if (! any_condjump_p (jump)) - return NULL_RTX; - - set = pc_set (jump); - - /* If this branches to JUMP_LABEL when the condition is false, - reverse the condition. */ - reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF - && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (jump)); - - /* We may have to reverse because the caller's if block is not canonical, - i.e. the THEN block isn't the fallthrough block for the TEST block - (see find_if_header). */ - if (then_else_reversed) - reverse = !reverse; - - /* If the condition variable is a register and is MODE_INT, accept it. */ - - cond = XEXP (SET_SRC (set), 0); - tmp = XEXP (cond, 0); - if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT - && (GET_MODE (tmp) != BImode - || !targetm.small_register_classes_for_mode_p (BImode))) - { - *earliest = jump; - - if (reverse) - cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), - GET_MODE (cond), tmp, XEXP (cond, 1)); - return cond; - } - - /* Otherwise, fall back on canonicalize_condition to do the dirty - work of manipulating MODE_CC values and COMPARE rtx codes. */ - tmp = canonicalize_condition (jump, cond, reverse, earliest, - NULL_RTX, have_cbranchcc4, true); - - /* We don't handle side-effects in the condition, like handling - REG_INC notes and making sure no duplicate conditions are emitted. */ - if (tmp != NULL_RTX && side_effects_p (tmp)) - return NULL_RTX; - - return tmp; -} - -/* Return true if OP is ok for if-then-else processing. */ - -static int -noce_operand_ok (const_rtx op) -{ - if (side_effects_p (op)) - return FALSE; - - /* We special-case memories, so handle any of them with - no address side effects. */ - if (MEM_P (op)) - return ! side_effects_p (XEXP (op, 0)); - - return ! may_trap_p (op); -} - -/* Return true iff basic block TEST_BB is valid for noce if-conversion. - The condition used in this if-conversion is in COND. - In practice, check that TEST_BB ends with a single set - x := a and all previous computations - in TEST_BB don't produce any values that are live after TEST_BB. - In other words, all the insns in TEST_BB are there only - to compute a value for x. Add the rtx cost of the insns - in TEST_BB to COST. Record whether TEST_BB is a single simple - set instruction in SIMPLE_P. */ - -static bool -bb_valid_for_noce_process_p (basic_block test_bb, rtx cond, - unsigned int *cost, bool *simple_p) -{ - if (!test_bb) - return false; - - rtx_insn *last_insn = last_active_insn (test_bb, FALSE); - rtx last_set = NULL_RTX; - - rtx cc = cc_in_cond (cond); - - if (!insn_valid_noce_process_p (last_insn, cc)) - return false; - - /* Punt on blocks ending with asm goto or jumps with other side-effects, - last_active_insn ignores JUMP_INSNs. */ - if (JUMP_P (BB_END (test_bb)) && !onlyjump_p (BB_END (test_bb))) - return false; - - last_set = single_set (last_insn); - - rtx x = SET_DEST (last_set); - rtx_insn *first_insn = first_active_insn (test_bb); - rtx first_set = single_set (first_insn); - - if (!first_set) - return false; - - /* We have a single simple set, that's okay. */ - bool speed_p = optimize_bb_for_speed_p (test_bb); - - if (first_insn == last_insn) - { - *simple_p = noce_operand_ok (SET_DEST (first_set)); - *cost += pattern_cost (first_set, speed_p); - return *simple_p; - } - - rtx_insn *prev_last_insn = PREV_INSN (last_insn); - gcc_assert (prev_last_insn); - - /* For now, disallow setting x multiple times in test_bb. */ - if (REG_P (x) && reg_set_between_p (x, first_insn, prev_last_insn)) - return false; - - bitmap test_bb_temps = BITMAP_ALLOC (®_obstack); - - /* The regs that are live out of test_bb. */ - bitmap test_bb_live_out = df_get_live_out (test_bb); - - int potential_cost = pattern_cost (last_set, speed_p); - rtx_insn *insn; - FOR_BB_INSNS (test_bb, insn) - { - if (insn != last_insn) - { - if (!active_insn_p (insn)) - continue; - - if (!insn_valid_noce_process_p (insn, cc)) - goto free_bitmap_and_fail; - - rtx sset = single_set (insn); - gcc_assert (sset); - - if (contains_mem_rtx_p (SET_SRC (sset)) - || !REG_P (SET_DEST (sset)) - || reg_overlap_mentioned_p (SET_DEST (sset), cond)) - goto free_bitmap_and_fail; - - potential_cost += pattern_cost (sset, speed_p); - bitmap_set_bit (test_bb_temps, REGNO (SET_DEST (sset))); - } - } - - /* If any of the intermediate results in test_bb are live after test_bb - then fail. */ - if (bitmap_intersect_p (test_bb_live_out, test_bb_temps)) - goto free_bitmap_and_fail; - - BITMAP_FREE (test_bb_temps); - *cost += potential_cost; - *simple_p = false; - return true; - - free_bitmap_and_fail: - BITMAP_FREE (test_bb_temps); - return false; -} - -/* We have something like: - - if (x > y) - { i = a; j = b; k = c; } - - Make it: - - tmp_i = (x > y) ? a : i; - tmp_j = (x > y) ? b : j; - tmp_k = (x > y) ? c : k; - i = tmp_i; - j = tmp_j; - k = tmp_k; - - Subsequent passes are expected to clean up the extra moves. - - Look for special cases such as writes to one register which are - read back in another SET, as might occur in a swap idiom or - similar. - - These look like: - - if (x > y) - i = a; - j = i; - - Which we want to rewrite to: - - tmp_i = (x > y) ? a : i; - tmp_j = (x > y) ? tmp_i : j; - i = tmp_i; - j = tmp_j; - - We can catch these when looking at (SET x y) by keeping a list of the - registers we would have targeted before if-conversion and looking back - through it for an overlap with Y. If we find one, we rewire the - conditional set to use the temporary we introduced earlier. - - IF_INFO contains the useful information about the block structure and - jump instructions. */ - -static int -noce_convert_multiple_sets (struct noce_if_info *if_info) -{ - basic_block test_bb = if_info->test_bb; - basic_block then_bb = if_info->then_bb; - basic_block join_bb = if_info->join_bb; - rtx_insn *jump = if_info->jump; - rtx_insn *cond_earliest; - rtx_insn *insn; - - start_sequence (); - - /* Decompose the condition attached to the jump. */ - rtx cond = noce_get_condition (jump, &cond_earliest, false); - rtx x = XEXP (cond, 0); - rtx y = XEXP (cond, 1); - rtx_code cond_code = GET_CODE (cond); - - /* The true targets for a conditional move. */ - auto_vec<rtx> targets; - /* The temporaries introduced to allow us to not consider register - overlap. */ - auto_vec<rtx> temporaries; - /* The insns we've emitted. */ - auto_vec<rtx_insn *> unmodified_insns; - int count = 0; - - FOR_BB_INSNS (then_bb, insn) - { - /* Skip over non-insns. */ - if (!active_insn_p (insn)) - continue; - - rtx set = single_set (insn); - gcc_checking_assert (set); - - rtx target = SET_DEST (set); - rtx temp = gen_reg_rtx (GET_MODE (target)); - rtx new_val = SET_SRC (set); - rtx old_val = target; - - /* If we were supposed to read from an earlier write in this block, - we've changed the register allocation. Rewire the read. While - we are looking, also try to catch a swap idiom. */ - for (int i = count - 1; i >= 0; --i) - if (reg_overlap_mentioned_p (new_val, targets[i])) - { - /* Catch a "swap" style idiom. */ - if (find_reg_note (insn, REG_DEAD, new_val) != NULL_RTX) - /* The write to targets[i] is only live until the read - here. As the condition codes match, we can propagate - the set to here. */ - new_val = SET_SRC (single_set (unmodified_insns[i])); - else - new_val = temporaries[i]; - break; - } - - /* If we had a non-canonical conditional jump (i.e. one where - the fallthrough is to the "else" case) we need to reverse - the conditional select. */ - if (if_info->then_else_reversed) - std::swap (old_val, new_val); - - - /* We allow simple lowpart register subreg SET sources in - bb_ok_for_noce_convert_multiple_sets. Be careful when processing - sequences like: - (set (reg:SI r1) (reg:SI r2)) - (set (reg:HI r3) (subreg:HI (r1))) - For the second insn new_val or old_val (r1 in this example) will be - taken from the temporaries and have the wider mode which will not - match with the mode of the other source of the conditional move, so - we'll end up trying to emit r4:HI = cond ? (r1:SI) : (r3:HI). - Wrap the two cmove operands into subregs if appropriate to prevent - that. */ - if (GET_MODE (new_val) != GET_MODE (temp)) - { - machine_mode src_mode = GET_MODE (new_val); - machine_mode dst_mode = GET_MODE (temp); - if (!partial_subreg_p (dst_mode, src_mode)) - { - end_sequence (); - return FALSE; - } - new_val = lowpart_subreg (dst_mode, new_val, src_mode); - } - if (GET_MODE (old_val) != GET_MODE (temp)) - { - machine_mode src_mode = GET_MODE (old_val); - machine_mode dst_mode = GET_MODE (temp); - if (!partial_subreg_p (dst_mode, src_mode)) - { - end_sequence (); - return FALSE; - } - old_val = lowpart_subreg (dst_mode, old_val, src_mode); - } - - /* Actually emit the conditional move. */ - rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code, - x, y, new_val, old_val); - - /* If we failed to expand the conditional move, drop out and don't - try to continue. */ - if (temp_dest == NULL_RTX) - { - end_sequence (); - return FALSE; - } - - /* Bookkeeping. */ - count++; - targets.safe_push (target); - temporaries.safe_push (temp_dest); - unmodified_insns.safe_push (insn); - } - - /* We must have seen some sort of insn to insert, otherwise we were - given an empty BB to convert, and we can't handle that. */ - gcc_assert (!unmodified_insns.is_empty ()); - - /* Now fixup the assignments. */ - for (int i = 0; i < count; i++) - noce_emit_move_insn (targets[i], temporaries[i]); - - /* Actually emit the sequence if it isn't too expensive. */ - rtx_insn *seq = get_insns (); - - if (!targetm.noce_conversion_profitable_p (seq, if_info)) - { - end_sequence (); - return FALSE; - } - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - set_used_flags (insn); - - /* Mark all our temporaries and targets as used. */ - for (int i = 0; i < count; i++) - { - set_used_flags (temporaries[i]); - set_used_flags (targets[i]); - } - - set_used_flags (cond); - set_used_flags (x); - set_used_flags (y); - - unshare_all_rtl_in_chain (seq); - end_sequence (); - - if (!seq) - return FALSE; - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - if (JUMP_P (insn) - || recog_memoized (insn) == -1) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (unmodified_insns.last ())); - - /* Clean up THEN_BB and the edges in and out of it. */ - remove_edge (find_edge (test_bb, join_bb)); - remove_edge (find_edge (then_bb, join_bb)); - redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb); - delete_basic_block (then_bb); - num_true_changes++; - - /* Maybe merge blocks now the jump is simple enough. */ - if (can_merge_blocks_p (test_bb, join_bb)) - { - merge_blocks (test_bb, join_bb); - num_true_changes++; - } - - num_updated_if_blocks++; - if_info->transform_name = "noce_convert_multiple_sets"; - return TRUE; -} - -/* Return true iff basic block TEST_BB is comprised of only - (SET (REG) (REG)) insns suitable for conversion to a series - of conditional moves. Also check that we have more than one set - (other routines can handle a single set better than we would), and - fewer than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets. */ - -static bool -bb_ok_for_noce_convert_multiple_sets (basic_block test_bb) -{ - rtx_insn *insn; - unsigned count = 0; - unsigned param = param_max_rtl_if_conversion_insns; - - FOR_BB_INSNS (test_bb, insn) - { - /* Skip over notes etc. */ - if (!active_insn_p (insn)) - continue; - - /* We only handle SET insns. */ - rtx set = single_set (insn); - if (set == NULL_RTX) - return false; - - rtx dest = SET_DEST (set); - rtx src = SET_SRC (set); - - /* We can possibly relax this, but for now only handle REG to REG - (including subreg) moves. This avoids any issues that might come - from introducing loads/stores that might violate data-race-freedom - guarantees. */ - if (!REG_P (dest)) - return false; - - if (!(REG_P (src) - || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) - && subreg_lowpart_p (src)))) - return false; - - /* Destination must be appropriate for a conditional write. */ - if (!noce_operand_ok (dest)) - return false; - - /* We must be able to conditionally move in this mode. */ - if (!can_conditionally_move_p (GET_MODE (dest))) - return false; - - count++; - } - - /* If we would only put out one conditional move, the other strategies - this pass tries are better optimized and will be more appropriate. - Some targets want to strictly limit the number of conditional moves - that are emitted, they set this through PARAM, we need to respect - that. */ - return count > 1 && count <= param; -} - -/* Compute average of two given costs weighted by relative probabilities - of respective basic blocks in an IF-THEN-ELSE. E is the IF-THEN edge. - With P as the probability to take the IF-THEN branch, return - P * THEN_COST + (1 - P) * ELSE_COST. */ -static unsigned -average_cost (unsigned then_cost, unsigned else_cost, edge e) -{ - return else_cost + e->probability.apply ((signed) (then_cost - else_cost)); -} - -/* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert - it without using conditional execution. Return TRUE if we were successful - at converting the block. */ - -static int -noce_process_if_block (struct noce_if_info *if_info) -{ - basic_block test_bb = if_info->test_bb; /* test block */ - basic_block then_bb = if_info->then_bb; /* THEN */ - basic_block else_bb = if_info->else_bb; /* ELSE or NULL */ - basic_block join_bb = if_info->join_bb; /* JOIN */ - rtx_insn *jump = if_info->jump; - rtx cond = if_info->cond; - rtx_insn *insn_a, *insn_b; - rtx set_a, set_b; - rtx orig_x, x, a, b; - - /* We're looking for patterns of the form - - (1) if (...) x = a; else x = b; - (2) x = b; if (...) x = a; - (3) if (...) x = a; // as if with an initial x = x. - (4) if (...) { x = a; y = b; z = c; } // Like 3, for multiple SETS. - The later patterns require jumps to be more expensive. - For the if (...) x = a; else x = b; case we allow multiple insns - inside the then and else blocks as long as their only effect is - to calculate a value for x. - ??? For future expansion, further expand the "multiple X" rules. */ - - /* First look for multiple SETS. */ - if (!else_bb - && HAVE_conditional_move - && bb_ok_for_noce_convert_multiple_sets (then_bb)) - { - if (noce_convert_multiple_sets (if_info)) - { - if (dump_file && if_info->transform_name) - fprintf (dump_file, "if-conversion succeeded through %s\n", - if_info->transform_name); - return TRUE; - } - } - - bool speed_p = optimize_bb_for_speed_p (test_bb); - unsigned int then_cost = 0, else_cost = 0; - if (!bb_valid_for_noce_process_p (then_bb, cond, &then_cost, - &if_info->then_simple)) - return false; - - if (else_bb - && !bb_valid_for_noce_process_p (else_bb, cond, &else_cost, - &if_info->else_simple)) - return false; - - if (speed_p) - if_info->original_cost += average_cost (then_cost, else_cost, - find_edge (test_bb, then_bb)); - else - if_info->original_cost += then_cost + else_cost; - - insn_a = last_active_insn (then_bb, FALSE); - set_a = single_set (insn_a); - gcc_assert (set_a); - - x = SET_DEST (set_a); - a = SET_SRC (set_a); - - /* Look for the other potential set. Make sure we've got equivalent - destinations. */ - /* ??? This is overconservative. Storing to two different mems is - as easy as conditionally computing the address. Storing to a - single mem merely requires a scratch memory to use as one of the - destination addresses; often the memory immediately below the - stack pointer is available for this. */ - set_b = NULL_RTX; - if (else_bb) - { - insn_b = last_active_insn (else_bb, FALSE); - set_b = single_set (insn_b); - gcc_assert (set_b); - - if (!rtx_interchangeable_p (x, SET_DEST (set_b))) - return FALSE; - } - else - { - insn_b = if_info->cond_earliest; - do - insn_b = prev_nonnote_nondebug_insn (insn_b); - while (insn_b - && (BLOCK_FOR_INSN (insn_b) - == BLOCK_FOR_INSN (if_info->cond_earliest)) - && !modified_in_p (x, insn_b)); - - /* We're going to be moving the evaluation of B down from above - COND_EARLIEST to JUMP. Make sure the relevant data is still - intact. */ - if (! insn_b - || BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (if_info->cond_earliest) - || !NONJUMP_INSN_P (insn_b) - || (set_b = single_set (insn_b)) == NULL_RTX - || ! rtx_interchangeable_p (x, SET_DEST (set_b)) - || ! noce_operand_ok (SET_SRC (set_b)) - || reg_overlap_mentioned_p (x, SET_SRC (set_b)) - || modified_between_p (SET_SRC (set_b), insn_b, jump) - /* Avoid extending the lifetime of hard registers on small - register class machines. */ - || (REG_P (SET_SRC (set_b)) - && HARD_REGISTER_P (SET_SRC (set_b)) - && targetm.small_register_classes_for_mode_p - (GET_MODE (SET_SRC (set_b)))) - /* Likewise with X. In particular this can happen when - noce_get_condition looks farther back in the instruction - stream than one might expect. */ - || reg_overlap_mentioned_p (x, cond) - || reg_overlap_mentioned_p (x, a) - || modified_between_p (x, insn_b, jump)) - { - insn_b = NULL; - set_b = NULL_RTX; - } - } - - /* If x has side effects then only the if-then-else form is safe to - convert. But even in that case we would need to restore any notes - (such as REG_INC) at then end. That can be tricky if - noce_emit_move_insn expands to more than one insn, so disable the - optimization entirely for now if there are side effects. */ - if (side_effects_p (x)) - return FALSE; - - b = (set_b ? SET_SRC (set_b) : x); - - /* Only operate on register destinations, and even then avoid extending - the lifetime of hard registers on small register class machines. */ - orig_x = x; - if_info->orig_x = orig_x; - if (!REG_P (x) - || (HARD_REGISTER_P (x) - && targetm.small_register_classes_for_mode_p (GET_MODE (x)))) - { - if (GET_MODE (x) == BLKmode) - return FALSE; - - if (GET_CODE (x) == ZERO_EXTRACT - && (!CONST_INT_P (XEXP (x, 1)) - || !CONST_INT_P (XEXP (x, 2)))) - return FALSE; - - x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART - ? XEXP (x, 0) : x)); - } - - /* Don't operate on sources that may trap or are volatile. */ - if (! noce_operand_ok (a) || ! noce_operand_ok (b)) - return FALSE; - - retry: - /* Set up the info block for our subroutines. */ - if_info->insn_a = insn_a; - if_info->insn_b = insn_b; - if_info->x = x; - if_info->a = a; - if_info->b = b; - - /* Try optimizations in some approximation of a useful order. */ - /* ??? Should first look to see if X is live incoming at all. If it - isn't, we don't need anything but an unconditional set. */ - - /* Look and see if A and B are really the same. Avoid creating silly - cmove constructs that no one will fix up later. */ - if (noce_simple_bbs (if_info) - && rtx_interchangeable_p (a, b)) - { - /* If we have an INSN_B, we don't have to create any new rtl. Just - move the instruction that we already have. If we don't have an - INSN_B, that means that A == X, and we've got a noop move. In - that case don't do anything and let the code below delete INSN_A. */ - if (insn_b && else_bb) - { - rtx note; - - if (else_bb && insn_b == BB_END (else_bb)) - BB_END (else_bb) = PREV_INSN (insn_b); - reorder_insns (insn_b, insn_b, PREV_INSN (jump)); - - /* If there was a REG_EQUAL note, delete it since it may have been - true due to this insn being after a jump. */ - if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0) - remove_note (insn_b, note); - - insn_b = NULL; - } - /* If we have "x = b; if (...) x = a;", and x has side-effects, then - x must be executed twice. */ - else if (insn_b && side_effects_p (orig_x)) - return FALSE; - - x = orig_x; - goto success; - } - - if (!set_b && MEM_P (orig_x)) - /* We want to avoid store speculation to avoid cases like - if (pthread_mutex_trylock(mutex)) - ++global_variable; - Rather than go to much effort here, we rely on the SSA optimizers, - which do a good enough job these days. */ - return FALSE; - - if (noce_try_move (if_info)) - goto success; - if (noce_try_ifelse_collapse (if_info)) - goto success; - if (noce_try_store_flag (if_info)) - goto success; - if (noce_try_bitop (if_info)) - goto success; - if (noce_try_minmax (if_info)) - goto success; - if (noce_try_abs (if_info)) - goto success; - if (noce_try_inverse_constants (if_info)) - goto success; - if (!targetm.have_conditional_execution () - && noce_try_store_flag_constants (if_info)) - goto success; - if (HAVE_conditional_move - && noce_try_cmove (if_info)) - goto success; - if (! targetm.have_conditional_execution ()) - { - if (noce_try_addcc (if_info)) - goto success; - if (noce_try_store_flag_mask (if_info)) - goto success; - if (HAVE_conditional_move - && noce_try_cmove_arith (if_info)) - goto success; - if (noce_try_sign_mask (if_info)) - goto success; - } - - if (!else_bb && set_b) - { - insn_b = NULL; - set_b = NULL_RTX; - b = orig_x; - goto retry; - } - - return FALSE; - - success: - if (dump_file && if_info->transform_name) - fprintf (dump_file, "if-conversion succeeded through %s\n", - if_info->transform_name); - - /* If we used a temporary, fix it up now. */ - if (orig_x != x) - { - rtx_insn *seq; - - start_sequence (); - noce_emit_move_insn (orig_x, x); - seq = get_insns (); - set_used_flags (orig_x); - unshare_all_rtl_in_chain (seq); - end_sequence (); - - emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATION (insn_a)); - } - - /* The original THEN and ELSE blocks may now be removed. The test block - must now jump to the join block. If the test block and the join block - can be merged, do so. */ - if (else_bb) - { - delete_basic_block (else_bb); - num_true_changes++; - } - else - remove_edge (find_edge (test_bb, join_bb)); - - remove_edge (find_edge (then_bb, join_bb)); - redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb); - delete_basic_block (then_bb); - num_true_changes++; - - if (can_merge_blocks_p (test_bb, join_bb)) - { - merge_blocks (test_bb, join_bb); - num_true_changes++; - } - - num_updated_if_blocks++; - return TRUE; -} - -/* Check whether a block is suitable for conditional move conversion. - Every insn must be a simple set of a register to a constant or a - register. For each assignment, store the value in the pointer map - VALS, keyed indexed by register pointer, then store the register - pointer in REGS. COND is the condition we will test. */ - -static int -check_cond_move_block (basic_block bb, - hash_map<rtx, rtx> *vals, - vec<rtx> *regs, - rtx cond) -{ - rtx_insn *insn; - rtx cc = cc_in_cond (cond); - - /* We can only handle simple jumps at the end of the basic block. - It is almost impossible to update the CFG otherwise. */ - insn = BB_END (bb); - if (JUMP_P (insn) && !onlyjump_p (insn)) - return FALSE; - - FOR_BB_INSNS (bb, insn) - { - rtx set, dest, src; - - if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) - continue; - set = single_set (insn); - if (!set) - return FALSE; - - dest = SET_DEST (set); - src = SET_SRC (set); - if (!REG_P (dest) - || (HARD_REGISTER_P (dest) - && targetm.small_register_classes_for_mode_p (GET_MODE (dest)))) - return FALSE; - - if (!CONSTANT_P (src) && !register_operand (src, VOIDmode)) - return FALSE; - - if (side_effects_p (src) || side_effects_p (dest)) - return FALSE; - - if (may_trap_p (src) || may_trap_p (dest)) - return FALSE; - - /* Don't try to handle this if the source register was - modified earlier in the block. */ - if ((REG_P (src) - && vals->get (src)) - || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) - && vals->get (SUBREG_REG (src)))) - return FALSE; - - /* Don't try to handle this if the destination register was - modified earlier in the block. */ - if (vals->get (dest)) - return FALSE; - - /* Don't try to handle this if the condition uses the - destination register. */ - if (reg_overlap_mentioned_p (dest, cond)) - return FALSE; - - /* Don't try to handle this if the source register is modified - later in the block. */ - if (!CONSTANT_P (src) - && modified_between_p (src, insn, NEXT_INSN (BB_END (bb)))) - return FALSE; - - /* Skip it if the instruction to be moved might clobber CC. */ - if (cc && set_of (cc, insn)) - return FALSE; - - vals->put (dest, src); - - regs->safe_push (dest); - } - - return TRUE; -} - -/* Given a basic block BB suitable for conditional move conversion, - a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing - the register values depending on COND, emit the insns in the block as - conditional moves. If ELSE_BLOCK is true, THEN_BB was already - processed. The caller has started a sequence for the conversion. - Return true if successful, false if something goes wrong. */ - -static bool -cond_move_convert_if_block (struct noce_if_info *if_infop, - basic_block bb, rtx cond, - hash_map<rtx, rtx> *then_vals, - hash_map<rtx, rtx> *else_vals, - bool else_block_p) -{ - enum rtx_code code; - rtx_insn *insn; - rtx cond_arg0, cond_arg1; - - code = GET_CODE (cond); - cond_arg0 = XEXP (cond, 0); - cond_arg1 = XEXP (cond, 1); - - FOR_BB_INSNS (bb, insn) - { - rtx set, target, dest, t, e; - - /* ??? Maybe emit conditional debug insn? */ - if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) - continue; - set = single_set (insn); - gcc_assert (set && REG_P (SET_DEST (set))); - - dest = SET_DEST (set); - - rtx *then_slot = then_vals->get (dest); - rtx *else_slot = else_vals->get (dest); - t = then_slot ? *then_slot : NULL_RTX; - e = else_slot ? *else_slot : NULL_RTX; - - if (else_block_p) - { - /* If this register was set in the then block, we already - handled this case there. */ - if (t) - continue; - t = dest; - gcc_assert (e); - } - else - { - gcc_assert (t); - if (!e) - e = dest; - } - - target = noce_emit_cmove (if_infop, dest, code, cond_arg0, cond_arg1, - t, e); - if (!target) - return false; - - if (target != dest) - noce_emit_move_insn (dest, target); - } - - return true; -} - -/* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert - it using only conditional moves. Return TRUE if we were successful at - converting the block. */ - -static int -cond_move_process_if_block (struct noce_if_info *if_info) -{ - basic_block test_bb = if_info->test_bb; - basic_block then_bb = if_info->then_bb; - basic_block else_bb = if_info->else_bb; - basic_block join_bb = if_info->join_bb; - rtx_insn *jump = if_info->jump; - rtx cond = if_info->cond; - rtx_insn *seq, *loc_insn; - int c; - vec<rtx> then_regs = vNULL; - vec<rtx> else_regs = vNULL; - int success_p = FALSE; - int limit = param_max_rtl_if_conversion_insns; - - /* Build a mapping for each block to the value used for each - register. */ - hash_map<rtx, rtx> then_vals; - hash_map<rtx, rtx> else_vals; - - /* Make sure the blocks are suitable. */ - if (!check_cond_move_block (then_bb, &then_vals, &then_regs, cond) - || (else_bb - && !check_cond_move_block (else_bb, &else_vals, &else_regs, cond))) - goto done; - - /* Make sure the blocks can be used together. If the same register - is set in both blocks, and is not set to a constant in both - cases, then both blocks must set it to the same register. We - have already verified that if it is set to a register, that the - source register does not change after the assignment. Also count - the number of registers set in only one of the blocks. */ - c = 0; - for (rtx reg : then_regs) - { - rtx *then_slot = then_vals.get (reg); - rtx *else_slot = else_vals.get (reg); - - gcc_checking_assert (then_slot); - if (!else_slot) - ++c; - else - { - rtx then_val = *then_slot; - rtx else_val = *else_slot; - if (!CONSTANT_P (then_val) && !CONSTANT_P (else_val) - && !rtx_equal_p (then_val, else_val)) - goto done; - } - } - - /* Finish off c for MAX_CONDITIONAL_EXECUTE. */ - for (rtx reg : else_regs) - { - gcc_checking_assert (else_vals.get (reg)); - if (!then_vals.get (reg)) - ++c; - } - - /* Make sure it is reasonable to convert this block. What matters - is the number of assignments currently made in only one of the - branches, since if we convert we are going to always execute - them. */ - if (c > MAX_CONDITIONAL_EXECUTE - || c > limit) - goto done; - - /* Try to emit the conditional moves. First do the then block, - then do anything left in the else blocks. */ - start_sequence (); - if (!cond_move_convert_if_block (if_info, then_bb, cond, - &then_vals, &else_vals, false) - || (else_bb - && !cond_move_convert_if_block (if_info, else_bb, cond, - &then_vals, &else_vals, true))) - { - end_sequence (); - goto done; - } - seq = end_ifcvt_sequence (if_info); - if (!seq) - goto done; - - loc_insn = first_active_insn (then_bb); - if (!loc_insn) - { - loc_insn = first_active_insn (else_bb); - gcc_assert (loc_insn); - } - emit_insn_before_setloc (seq, jump, INSN_LOCATION (loc_insn)); - - if (else_bb) - { - delete_basic_block (else_bb); - num_true_changes++; - } - else - remove_edge (find_edge (test_bb, join_bb)); - - remove_edge (find_edge (then_bb, join_bb)); - redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb); - delete_basic_block (then_bb); - num_true_changes++; - - if (can_merge_blocks_p (test_bb, join_bb)) - { - merge_blocks (test_bb, join_bb); - num_true_changes++; - } - - num_updated_if_blocks++; - success_p = TRUE; - -done: - then_regs.release (); - else_regs.release (); - return success_p; -} - - -/* Determine if a given basic block heads a simple IF-THEN-JOIN or an - IF-THEN-ELSE-JOIN block. - - If so, we'll try to convert the insns to not require the branch, - using only transformations that do not require conditional execution. - - Return TRUE if we were successful at converting the block. */ - -static int -noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge, - int pass) -{ - basic_block then_bb, else_bb, join_bb; - bool then_else_reversed = false; - rtx_insn *jump; - rtx cond; - rtx_insn *cond_earliest; - struct noce_if_info if_info; - bool speed_p = optimize_bb_for_speed_p (test_bb); - - /* We only ever should get here before reload. */ - gcc_assert (!reload_completed); - - /* Recognize an IF-THEN-ELSE-JOIN block. */ - if (single_pred_p (then_edge->dest) - && single_succ_p (then_edge->dest) - && single_pred_p (else_edge->dest) - && single_succ_p (else_edge->dest) - && single_succ (then_edge->dest) == single_succ (else_edge->dest)) - { - then_bb = then_edge->dest; - else_bb = else_edge->dest; - join_bb = single_succ (then_bb); - } - /* Recognize an IF-THEN-JOIN block. */ - else if (single_pred_p (then_edge->dest) - && single_succ_p (then_edge->dest) - && single_succ (then_edge->dest) == else_edge->dest) - { - then_bb = then_edge->dest; - else_bb = NULL_BLOCK; - join_bb = else_edge->dest; - } - /* Recognize an IF-ELSE-JOIN block. We can have those because the order - of basic blocks in cfglayout mode does not matter, so the fallthrough - edge can go to any basic block (and not just to bb->next_bb, like in - cfgrtl mode). */ - else if (single_pred_p (else_edge->dest) - && single_succ_p (else_edge->dest) - && single_succ (else_edge->dest) == then_edge->dest) - { - /* The noce transformations do not apply to IF-ELSE-JOIN blocks. - To make this work, we have to invert the THEN and ELSE blocks - and reverse the jump condition. */ - then_bb = else_edge->dest; - else_bb = NULL_BLOCK; - join_bb = single_succ (then_bb); - then_else_reversed = true; - } - else - /* Not a form we can handle. */ - return FALSE; - - /* The edges of the THEN and ELSE blocks cannot have complex edges. */ - if (single_succ_edge (then_bb)->flags & EDGE_COMPLEX) - return FALSE; - if (else_bb - && single_succ_edge (else_bb)->flags & EDGE_COMPLEX) - return FALSE; - - num_possible_if_blocks++; - - if (dump_file) - { - fprintf (dump_file, - "\nIF-THEN%s-JOIN block found, pass %d, test %d, then %d", - (else_bb) ? "-ELSE" : "", - pass, test_bb->index, then_bb->index); - - if (else_bb) - fprintf (dump_file, ", else %d", else_bb->index); - - fprintf (dump_file, ", join %d\n", join_bb->index); - } - - /* If the conditional jump is more than just a conditional - jump, then we cannot do if-conversion on this block. */ - jump = BB_END (test_bb); - if (! onlyjump_p (jump)) - return FALSE; - - /* If this is not a standard conditional jump, we can't parse it. */ - cond = noce_get_condition (jump, &cond_earliest, then_else_reversed); - if (!cond) - return FALSE; - - /* We must be comparing objects whose modes imply the size. */ - if (GET_MODE (XEXP (cond, 0)) == BLKmode) - return FALSE; - - /* Initialize an IF_INFO struct to pass around. */ - memset (&if_info, 0, sizeof if_info); - if_info.test_bb = test_bb; - if_info.then_bb = then_bb; - if_info.else_bb = else_bb; - if_info.join_bb = join_bb; - if_info.cond = cond; - rtx_insn *rev_cond_earliest; - if_info.rev_cond = noce_get_condition (jump, &rev_cond_earliest, - !then_else_reversed); - gcc_assert (if_info.rev_cond == NULL_RTX - || rev_cond_earliest == cond_earliest); - if_info.cond_earliest = cond_earliest; - if_info.jump = jump; - if_info.then_else_reversed = then_else_reversed; - if_info.speed_p = speed_p; - if_info.max_seq_cost - = targetm.max_noce_ifcvt_seq_cost (then_edge); - /* We'll add in the cost of THEN_BB and ELSE_BB later, when we check - that they are valid to transform. We can't easily get back to the insn - for COND (and it may not exist if we had to canonicalize to get COND), - and jump_insns are always given a cost of 1 by seq_cost, so treat - both instructions as having cost COSTS_N_INSNS (1). */ - if_info.original_cost = COSTS_N_INSNS (2); - - - /* Do the real work. */ - - if (noce_process_if_block (&if_info)) - return TRUE; - - if (HAVE_conditional_move - && cond_move_process_if_block (&if_info)) - return TRUE; - - return FALSE; -} - - -/* Merge the blocks and mark for local life update. */ - -static void -merge_if_block (struct ce_if_block * ce_info) -{ - basic_block test_bb = ce_info->test_bb; /* last test block */ - basic_block then_bb = ce_info->then_bb; /* THEN */ - basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */ - basic_block join_bb = ce_info->join_bb; /* join block */ - basic_block combo_bb; - - /* All block merging is done into the lower block numbers. */ - - combo_bb = test_bb; - df_set_bb_dirty (test_bb); - - /* Merge any basic blocks to handle && and || subtests. Each of - the blocks are on the fallthru path from the predecessor block. */ - if (ce_info->num_multiple_test_blocks > 0) - { - basic_block bb = test_bb; - basic_block last_test_bb = ce_info->last_test_bb; - basic_block fallthru = block_fallthru (bb); - - do - { - bb = fallthru; - fallthru = block_fallthru (bb); - merge_blocks (combo_bb, bb); - num_true_changes++; - } - while (bb != last_test_bb); - } - - /* Merge TEST block into THEN block. Normally the THEN block won't have a - label, but it might if there were || tests. That label's count should be - zero, and it normally should be removed. */ - - if (then_bb) - { - /* If THEN_BB has no successors, then there's a BARRIER after it. - If COMBO_BB has more than one successor (THEN_BB), then that BARRIER - is no longer needed, and in fact it is incorrect to leave it in - the insn stream. */ - if (EDGE_COUNT (then_bb->succs) == 0 - && EDGE_COUNT (combo_bb->succs) > 1) - { - rtx_insn *end = NEXT_INSN (BB_END (then_bb)); - while (end && NOTE_P (end) && !NOTE_INSN_BASIC_BLOCK_P (end)) - end = NEXT_INSN (end); - - if (end && BARRIER_P (end)) - delete_insn (end); - } - merge_blocks (combo_bb, then_bb); - num_true_changes++; - } - - /* The ELSE block, if it existed, had a label. That label count - will almost always be zero, but odd things can happen when labels - get their addresses taken. */ - if (else_bb) - { - /* If ELSE_BB has no successors, then there's a BARRIER after it. - If COMBO_BB has more than one successor (ELSE_BB), then that BARRIER - is no longer needed, and in fact it is incorrect to leave it in - the insn stream. */ - if (EDGE_COUNT (else_bb->succs) == 0 - && EDGE_COUNT (combo_bb->succs) > 1) - { - rtx_insn *end = NEXT_INSN (BB_END (else_bb)); - while (end && NOTE_P (end) && !NOTE_INSN_BASIC_BLOCK_P (end)) - end = NEXT_INSN (end); - - if (end && BARRIER_P (end)) - delete_insn (end); - } - merge_blocks (combo_bb, else_bb); - num_true_changes++; - } - - /* If there was no join block reported, that means it was not adjacent - to the others, and so we cannot merge them. */ - - if (! join_bb) - { - rtx_insn *last = BB_END (combo_bb); - - /* The outgoing edge for the current COMBO block should already - be correct. Verify this. */ - if (EDGE_COUNT (combo_bb->succs) == 0) - gcc_assert (find_reg_note (last, REG_NORETURN, NULL) - || (NONJUMP_INSN_P (last) - && GET_CODE (PATTERN (last)) == TRAP_IF - && (TRAP_CONDITION (PATTERN (last)) - == const_true_rtx))); - - else - /* There should still be something at the end of the THEN or ELSE - blocks taking us to our final destination. */ - gcc_assert (JUMP_P (last) - || (EDGE_SUCC (combo_bb, 0)->dest - == EXIT_BLOCK_PTR_FOR_FN (cfun) - && CALL_P (last) - && SIBLING_CALL_P (last)) - || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH) - && can_throw_internal (last))); - } - - /* The JOIN block may have had quite a number of other predecessors too. - Since we've already merged the TEST, THEN and ELSE blocks, we should - have only one remaining edge from our if-then-else diamond. If there - is more than one remaining edge, it must come from elsewhere. There - may be zero incoming edges if the THEN block didn't actually join - back up (as with a call to a non-return function). */ - else if (EDGE_COUNT (join_bb->preds) < 2 - && join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - /* We can merge the JOIN cleanly and update the dataflow try - again on this pass.*/ - merge_blocks (combo_bb, join_bb); - num_true_changes++; - } - else - { - /* We cannot merge the JOIN. */ - - /* The outgoing edge for the current COMBO block should already - be correct. Verify this. */ - gcc_assert (single_succ_p (combo_bb) - && single_succ (combo_bb) == join_bb); - - /* Remove the jump and cruft from the end of the COMBO block. */ - if (join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - tidy_fallthru_edge (single_succ_edge (combo_bb)); - } - - num_updated_if_blocks++; -} - -/* Find a block ending in a simple IF condition and try to transform it - in some way. When converting a multi-block condition, put the new code - in the first such block and delete the rest. Return a pointer to this - first block if some transformation was done. Return NULL otherwise. */ - -static basic_block -find_if_header (basic_block test_bb, int pass) -{ - ce_if_block ce_info; - edge then_edge; - edge else_edge; - - /* The kind of block we're looking for has exactly two successors. */ - if (EDGE_COUNT (test_bb->succs) != 2) - return NULL; - - then_edge = EDGE_SUCC (test_bb, 0); - else_edge = EDGE_SUCC (test_bb, 1); - - if (df_get_bb_dirty (then_edge->dest)) - return NULL; - if (df_get_bb_dirty (else_edge->dest)) - return NULL; - - /* Neither edge should be abnormal. */ - if ((then_edge->flags & EDGE_COMPLEX) - || (else_edge->flags & EDGE_COMPLEX)) - return NULL; - - /* Nor exit the loop. */ - if ((then_edge->flags & EDGE_LOOP_EXIT) - || (else_edge->flags & EDGE_LOOP_EXIT)) - return NULL; - - /* The THEN edge is canonically the one that falls through. */ - if (then_edge->flags & EDGE_FALLTHRU) - ; - else if (else_edge->flags & EDGE_FALLTHRU) - std::swap (then_edge, else_edge); - else - /* Otherwise this must be a multiway branch of some sort. */ - return NULL; - - memset (&ce_info, 0, sizeof (ce_info)); - ce_info.test_bb = test_bb; - ce_info.then_bb = then_edge->dest; - ce_info.else_bb = else_edge->dest; - ce_info.pass = pass; - -#ifdef IFCVT_MACHDEP_INIT - IFCVT_MACHDEP_INIT (&ce_info); -#endif - - if (!reload_completed - && noce_find_if_block (test_bb, then_edge, else_edge, pass)) - goto success; - - if (reload_completed - && targetm.have_conditional_execution () - && cond_exec_find_if_block (&ce_info)) - goto success; - - if (targetm.have_trap () - && optab_handler (ctrap_optab, word_mode) != CODE_FOR_nothing - && find_cond_trap (test_bb, then_edge, else_edge)) - goto success; - - if (dom_info_state (CDI_POST_DOMINATORS) >= DOM_NO_FAST_QUERY - && (reload_completed || !targetm.have_conditional_execution ())) - { - if (find_if_case_1 (test_bb, then_edge, else_edge)) - goto success; - if (find_if_case_2 (test_bb, then_edge, else_edge)) - goto success; - } - - return NULL; - - success: - if (dump_file) - fprintf (dump_file, "Conversion succeeded on pass %d.\n", pass); - /* Set this so we continue looking. */ - cond_exec_changed_p = TRUE; - return ce_info.test_bb; -} - -/* Return true if a block has two edges, one of which falls through to the next - block, and the other jumps to a specific block, so that we can tell if the - block is part of an && test or an || test. Returns either -1 or the number - of non-note, non-jump, non-USE/CLOBBER insns in the block. */ - -static int -block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb) -{ - edge cur_edge; - int fallthru_p = FALSE; - int jump_p = FALSE; - rtx_insn *insn; - rtx_insn *end; - int n_insns = 0; - edge_iterator ei; - - if (!cur_bb || !target_bb) - return -1; - - /* If no edges, obviously it doesn't jump or fallthru. */ - if (EDGE_COUNT (cur_bb->succs) == 0) - return FALSE; - - FOR_EACH_EDGE (cur_edge, ei, cur_bb->succs) - { - if (cur_edge->flags & EDGE_COMPLEX) - /* Anything complex isn't what we want. */ - return -1; - - else if (cur_edge->flags & EDGE_FALLTHRU) - fallthru_p = TRUE; - - else if (cur_edge->dest == target_bb) - jump_p = TRUE; - - else - return -1; - } - - if ((jump_p & fallthru_p) == 0) - return -1; - - /* Don't allow calls in the block, since this is used to group && and || - together for conditional execution support. ??? we should support - conditional execution support across calls for IA-64 some day, but - for now it makes the code simpler. */ - end = BB_END (cur_bb); - insn = BB_HEAD (cur_bb); - - while (insn != NULL_RTX) - { - if (CALL_P (insn)) - return -1; - - if (INSN_P (insn) - && !JUMP_P (insn) - && !DEBUG_INSN_P (insn) - && GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER) - n_insns++; - - if (insn == end) - break; - - insn = NEXT_INSN (insn); - } - - return n_insns; -} - -/* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE - block. If so, we'll try to convert the insns to not require the branch. - Return TRUE if we were successful at converting the block. */ - -static int -cond_exec_find_if_block (struct ce_if_block * ce_info) -{ - basic_block test_bb = ce_info->test_bb; - basic_block then_bb = ce_info->then_bb; - basic_block else_bb = ce_info->else_bb; - basic_block join_bb = NULL_BLOCK; - edge cur_edge; - basic_block next; - edge_iterator ei; - - ce_info->last_test_bb = test_bb; - - /* We only ever should get here after reload, - and if we have conditional execution. */ - gcc_assert (reload_completed && targetm.have_conditional_execution ()); - - /* Discover if any fall through predecessors of the current test basic block - were && tests (which jump to the else block) or || tests (which jump to - the then block). */ - if (single_pred_p (test_bb) - && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU) - { - basic_block bb = single_pred (test_bb); - basic_block target_bb; - int max_insns = MAX_CONDITIONAL_EXECUTE; - int n_insns; - - /* Determine if the preceding block is an && or || block. */ - if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0) - { - ce_info->and_and_p = TRUE; - target_bb = else_bb; - } - else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0) - { - ce_info->and_and_p = FALSE; - target_bb = then_bb; - } - else - target_bb = NULL_BLOCK; - - if (target_bb && n_insns <= max_insns) - { - int total_insns = 0; - int blocks = 0; - - ce_info->last_test_bb = test_bb; - - /* Found at least one && or || block, look for more. */ - do - { - ce_info->test_bb = test_bb = bb; - total_insns += n_insns; - blocks++; - - if (!single_pred_p (bb)) - break; - - bb = single_pred (bb); - n_insns = block_jumps_and_fallthru_p (bb, target_bb); - } - while (n_insns >= 0 && (total_insns + n_insns) <= max_insns); - - ce_info->num_multiple_test_blocks = blocks; - ce_info->num_multiple_test_insns = total_insns; - - if (ce_info->and_and_p) - ce_info->num_and_and_blocks = blocks; - else - ce_info->num_or_or_blocks = blocks; - } - } - - /* The THEN block of an IF-THEN combo must have exactly one predecessor, - other than any || blocks which jump to the THEN block. */ - if ((EDGE_COUNT (then_bb->preds) - ce_info->num_or_or_blocks) != 1) - return FALSE; - - /* The edges of the THEN and ELSE blocks cannot have complex edges. */ - FOR_EACH_EDGE (cur_edge, ei, then_bb->preds) - { - if (cur_edge->flags & EDGE_COMPLEX) - return FALSE; - } - - FOR_EACH_EDGE (cur_edge, ei, else_bb->preds) - { - if (cur_edge->flags & EDGE_COMPLEX) - return FALSE; - } - - /* The THEN block of an IF-THEN combo must have zero or one successors. */ - if (EDGE_COUNT (then_bb->succs) > 0 - && (!single_succ_p (then_bb) - || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX) - || (epilogue_completed - && tablejump_p (BB_END (then_bb), NULL, NULL)))) - return FALSE; - - /* If the THEN block has no successors, conditional execution can still - make a conditional call. Don't do this unless the ELSE block has - only one incoming edge -- the CFG manipulation is too ugly otherwise. - Check for the last insn of the THEN block being an indirect jump, which - is listed as not having any successors, but confuses the rest of the CE - code processing. ??? we should fix this in the future. */ - if (EDGE_COUNT (then_bb->succs) == 0) - { - if (single_pred_p (else_bb) && else_bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - rtx_insn *last_insn = BB_END (then_bb); - - while (last_insn - && NOTE_P (last_insn) - && last_insn != BB_HEAD (then_bb)) - last_insn = PREV_INSN (last_insn); - - if (last_insn - && JUMP_P (last_insn) - && ! simplejump_p (last_insn)) - return FALSE; - - join_bb = else_bb; - else_bb = NULL_BLOCK; - } - else - return FALSE; - } - - /* If the THEN block's successor is the other edge out of the TEST block, - then we have an IF-THEN combo without an ELSE. */ - else if (single_succ (then_bb) == else_bb) - { - join_bb = else_bb; - else_bb = NULL_BLOCK; - } - - /* If the THEN and ELSE block meet in a subsequent block, and the ELSE - has exactly one predecessor and one successor, and the outgoing edge - is not complex, then we have an IF-THEN-ELSE combo. */ - else if (single_succ_p (else_bb) - && single_succ (then_bb) == single_succ (else_bb) - && single_pred_p (else_bb) - && !(single_succ_edge (else_bb)->flags & EDGE_COMPLEX) - && !(epilogue_completed - && tablejump_p (BB_END (else_bb), NULL, NULL))) - join_bb = single_succ (else_bb); - - /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination. */ - else - return FALSE; - - num_possible_if_blocks++; - - if (dump_file) - { - fprintf (dump_file, - "\nIF-THEN%s block found, pass %d, start block %d " - "[insn %d], then %d [%d]", - (else_bb) ? "-ELSE" : "", - ce_info->pass, - test_bb->index, - BB_HEAD (test_bb) ? (int)INSN_UID (BB_HEAD (test_bb)) : -1, - then_bb->index, - BB_HEAD (then_bb) ? (int)INSN_UID (BB_HEAD (then_bb)) : -1); - - if (else_bb) - fprintf (dump_file, ", else %d [%d]", - else_bb->index, - BB_HEAD (else_bb) ? (int)INSN_UID (BB_HEAD (else_bb)) : -1); - - fprintf (dump_file, ", join %d [%d]", - join_bb->index, - BB_HEAD (join_bb) ? (int)INSN_UID (BB_HEAD (join_bb)) : -1); - - if (ce_info->num_multiple_test_blocks > 0) - fprintf (dump_file, ", %d %s block%s last test %d [%d]", - ce_info->num_multiple_test_blocks, - (ce_info->and_and_p) ? "&&" : "||", - (ce_info->num_multiple_test_blocks == 1) ? "" : "s", - ce_info->last_test_bb->index, - ((BB_HEAD (ce_info->last_test_bb)) - ? (int)INSN_UID (BB_HEAD (ce_info->last_test_bb)) - : -1)); - - fputc ('\n', dump_file); - } - - /* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we get the - first condition for free, since we've already asserted that there's a - fallthru edge from IF to THEN. Likewise for the && and || blocks, since - we checked the FALLTHRU flag, those are already adjacent to the last IF - block. */ - /* ??? As an enhancement, move the ELSE block. Have to deal with - BLOCK notes, if by no other means than backing out the merge if they - exist. Sticky enough I don't want to think about it now. */ - next = then_bb; - if (else_bb && (next = next->next_bb) != else_bb) - return FALSE; - if ((next = next->next_bb) != join_bb - && join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - if (else_bb) - join_bb = NULL; - else - return FALSE; - } - - /* Do the real work. */ - - ce_info->else_bb = else_bb; - ce_info->join_bb = join_bb; - - /* If we have && and || tests, try to first handle combining the && and || - tests into the conditional code, and if that fails, go back and handle - it without the && and ||, which at present handles the && case if there - was no ELSE block. */ - if (cond_exec_process_if_block (ce_info, TRUE)) - return TRUE; - - if (ce_info->num_multiple_test_blocks) - { - cancel_changes (0); - - if (cond_exec_process_if_block (ce_info, FALSE)) - return TRUE; - } - - return FALSE; -} - -/* Convert a branch over a trap, or a branch - to a trap, into a conditional trap. */ - -static int -find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge) -{ - basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; - basic_block other_bb, trap_bb; - rtx_insn *trap, *jump; - rtx cond; - rtx_insn *cond_earliest; - - /* Locate the block with the trap instruction. */ - /* ??? While we look for no successors, we really ought to allow - EH successors. Need to fix merge_if_block for that to work. */ - if ((trap = block_has_only_trap (then_bb)) != NULL) - trap_bb = then_bb, other_bb = else_bb; - else if ((trap = block_has_only_trap (else_bb)) != NULL) - trap_bb = else_bb, other_bb = then_bb; - else - return FALSE; - - if (dump_file) - { - fprintf (dump_file, "\nTRAP-IF block found, start %d, trap %d\n", - test_bb->index, trap_bb->index); - } - - /* If this is not a standard conditional jump, we can't parse it. */ - jump = BB_END (test_bb); - cond = noce_get_condition (jump, &cond_earliest, then_bb == trap_bb); - if (! cond) - return FALSE; - - /* If the conditional jump is more than just a conditional jump, then - we cannot do if-conversion on this block. Give up for returnjump_p, - changing a conditional return followed by unconditional trap for - conditional trap followed by unconditional return is likely not - beneficial and harder to handle. */ - if (! onlyjump_p (jump) || returnjump_p (jump)) - return FALSE; - - /* We must be comparing objects whose modes imply the size. */ - if (GET_MODE (XEXP (cond, 0)) == BLKmode) - return FALSE; - - /* Attempt to generate the conditional trap. */ - rtx_insn *seq = gen_cond_trap (GET_CODE (cond), copy_rtx (XEXP (cond, 0)), - copy_rtx (XEXP (cond, 1)), - TRAP_CODE (PATTERN (trap))); - if (seq == NULL) - return FALSE; - - /* If that results in an invalid insn, back out. */ - for (rtx_insn *x = seq; x; x = NEXT_INSN (x)) - if (reload_completed - ? !valid_insn_p (x) - : recog_memoized (x) < 0) - return FALSE; - - /* Emit the new insns before cond_earliest. */ - emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATION (trap)); - - /* Delete the trap block if possible. */ - remove_edge (trap_bb == then_bb ? then_edge : else_edge); - df_set_bb_dirty (test_bb); - df_set_bb_dirty (then_bb); - df_set_bb_dirty (else_bb); - - if (EDGE_COUNT (trap_bb->preds) == 0) - { - delete_basic_block (trap_bb); - num_true_changes++; - } - - /* Wire together the blocks again. */ - if (current_ir_type () == IR_RTL_CFGLAYOUT) - single_succ_edge (test_bb)->flags |= EDGE_FALLTHRU; - else if (trap_bb == then_bb) - { - rtx lab = JUMP_LABEL (jump); - rtx_insn *seq = targetm.gen_jump (lab); - rtx_jump_insn *newjump = emit_jump_insn_after (seq, jump); - LABEL_NUSES (lab) += 1; - JUMP_LABEL (newjump) = lab; - emit_barrier_after (newjump); - } - delete_insn (jump); - - if (can_merge_blocks_p (test_bb, other_bb)) - { - merge_blocks (test_bb, other_bb); - num_true_changes++; - } - - num_updated_if_blocks++; - return TRUE; -} - -/* Subroutine of find_cond_trap: if BB contains only a trap insn, - return it. */ - -static rtx_insn * -block_has_only_trap (basic_block bb) -{ - rtx_insn *trap; - - /* We're not the exit block. */ - if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun)) - return NULL; - - /* The block must have no successors. */ - if (EDGE_COUNT (bb->succs) > 0) - return NULL; - - /* The only instruction in the THEN block must be the trap. */ - trap = first_active_insn (bb); - if (! (trap == BB_END (bb) - && GET_CODE (PATTERN (trap)) == TRAP_IF - && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx)) - return NULL; - - return trap; -} - -/* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is - transformable, but not necessarily the other. There need be no - JOIN block. - - Return TRUE if we were successful at converting the block. - - Cases we'd like to look at: - - (1) - if (test) goto over; // x not live - x = a; - goto label; - over: - - becomes - - x = a; - if (! test) goto label; - - (2) - if (test) goto E; // x not live - x = big(); - goto L; - E: - x = b; - goto M; - - becomes - - x = b; - if (test) goto M; - x = big(); - goto L; - - (3) // This one's really only interesting for targets that can do - // multiway branching, e.g. IA-64 BBB bundles. For other targets - // it results in multiple branches on a cache line, which often - // does not sit well with predictors. - - if (test1) goto E; // predicted not taken - x = a; - if (test2) goto F; - ... - E: - x = b; - J: - - becomes - - x = a; - if (test1) goto E; - if (test2) goto F; - - Notes: - - (A) Don't do (2) if the branch is predicted against the block we're - eliminating. Do it anyway if we can eliminate a branch; this requires - that the sole successor of the eliminated block postdominate the other - side of the if. - - (B) With CE, on (3) we can steal from both sides of the if, creating - - if (test1) x = a; - if (!test1) x = b; - if (test1) goto J; - if (test2) goto F; - ... - J: - - Again, this is most useful if J postdominates. - - (C) CE substitutes for helpful life information. - - (D) These heuristics need a lot of work. */ - -/* Tests for case 1 above. */ - -static int -find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge) -{ - basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; - basic_block new_bb; - int then_bb_index; - profile_probability then_prob; - rtx else_target = NULL_RTX; - - /* If we are partitioning hot/cold basic blocks, we don't want to - mess up unconditional or indirect jumps that cross between hot - and cold sections. - - Basic block partitioning may result in some jumps that appear to - be optimizable (or blocks that appear to be mergeable), but which really - must be left untouched (they are required to make it safely across - partition boundaries). See the comments at the top of - bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */ - - if ((BB_END (then_bb) - && JUMP_P (BB_END (then_bb)) - && CROSSING_JUMP_P (BB_END (then_bb))) - || (BB_END (test_bb) - && JUMP_P (BB_END (test_bb)) - && CROSSING_JUMP_P (BB_END (test_bb))) - || (BB_END (else_bb) - && JUMP_P (BB_END (else_bb)) - && CROSSING_JUMP_P (BB_END (else_bb)))) - return FALSE; - - /* THEN has one successor. */ - if (!single_succ_p (then_bb)) - return FALSE; - - /* THEN does not fall through, but is not strange either. */ - if (single_succ_edge (then_bb)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU)) - return FALSE; - - /* THEN has one predecessor. */ - if (!single_pred_p (then_bb)) - return FALSE; - - /* THEN must do something. */ - if (forwarder_block_p (then_bb)) - return FALSE; - - num_possible_if_blocks++; - if (dump_file) - fprintf (dump_file, - "\nIF-CASE-1 found, start %d, then %d\n", - test_bb->index, then_bb->index); - - then_prob = then_edge->probability.invert (); - - /* We're speculating from the THEN path, we want to make sure the cost - of speculation is within reason. */ - if (! cheap_bb_rtx_cost_p (then_bb, then_prob, - COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (then_edge->src), - predictable_edge_p (then_edge))))) - return FALSE; - - if (else_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - rtx_insn *jump = BB_END (else_edge->src); - gcc_assert (JUMP_P (jump)); - else_target = JUMP_LABEL (jump); - } - - /* Registers set are dead, or are predicable. */ - if (! dead_or_predicable (test_bb, then_bb, else_bb, - single_succ_edge (then_bb), 1)) - return FALSE; - - /* Conversion went ok, including moving the insns and fixing up the - jump. Adjust the CFG to match. */ - - /* We can avoid creating a new basic block if then_bb is immediately - followed by else_bb, i.e. deleting then_bb allows test_bb to fall - through to else_bb. */ - - if (then_bb->next_bb == else_bb - && then_bb->prev_bb == test_bb - && else_bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb); - new_bb = 0; - } - else if (else_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)) - new_bb = force_nonfallthru_and_redirect (FALLTHRU_EDGE (test_bb), - else_bb, else_target); - else - new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), - else_bb); - - df_set_bb_dirty (test_bb); - df_set_bb_dirty (else_bb); - - then_bb_index = then_bb->index; - delete_basic_block (then_bb); - - /* Make rest of code believe that the newly created block is the THEN_BB - block we removed. */ - if (new_bb) - { - df_bb_replace (then_bb_index, new_bb); - /* This should have been done above via force_nonfallthru_and_redirect - (possibly called from redirect_edge_and_branch_force). */ - gcc_checking_assert (BB_PARTITION (new_bb) == BB_PARTITION (test_bb)); - } - - num_true_changes++; - num_updated_if_blocks++; - return TRUE; -} - -/* Test for case 2 above. */ - -static int -find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge) -{ - basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; - edge else_succ; - profile_probability then_prob, else_prob; - - /* We do not want to speculate (empty) loop latches. */ - if (current_loops - && else_bb->loop_father->latch == else_bb) - return FALSE; - - /* If we are partitioning hot/cold basic blocks, we don't want to - mess up unconditional or indirect jumps that cross between hot - and cold sections. - - Basic block partitioning may result in some jumps that appear to - be optimizable (or blocks that appear to be mergeable), but which really - must be left untouched (they are required to make it safely across - partition boundaries). See the comments at the top of - bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */ - - if ((BB_END (then_bb) - && JUMP_P (BB_END (then_bb)) - && CROSSING_JUMP_P (BB_END (then_bb))) - || (BB_END (test_bb) - && JUMP_P (BB_END (test_bb)) - && CROSSING_JUMP_P (BB_END (test_bb))) - || (BB_END (else_bb) - && JUMP_P (BB_END (else_bb)) - && CROSSING_JUMP_P (BB_END (else_bb)))) - return FALSE; - - /* ELSE has one successor. */ - if (!single_succ_p (else_bb)) - return FALSE; - else - else_succ = single_succ_edge (else_bb); - - /* ELSE outgoing edge is not complex. */ - if (else_succ->flags & EDGE_COMPLEX) - return FALSE; - - /* ELSE has one predecessor. */ - if (!single_pred_p (else_bb)) - return FALSE; - - /* THEN is not EXIT. */ - if (then_bb->index < NUM_FIXED_BLOCKS) - return FALSE; - - else_prob = else_edge->probability; - then_prob = else_prob.invert (); - - /* ELSE is predicted or SUCC(ELSE) postdominates THEN. */ - if (else_prob > then_prob) - ; - else if (else_succ->dest->index < NUM_FIXED_BLOCKS - || dominated_by_p (CDI_POST_DOMINATORS, then_bb, - else_succ->dest)) - ; - else - return FALSE; - - num_possible_if_blocks++; - if (dump_file) - fprintf (dump_file, - "\nIF-CASE-2 found, start %d, else %d\n", - test_bb->index, else_bb->index); - - /* We're speculating from the ELSE path, we want to make sure the cost - of speculation is within reason. */ - if (! cheap_bb_rtx_cost_p (else_bb, else_prob, - COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (else_edge->src), - predictable_edge_p (else_edge))))) - return FALSE; - - /* Registers set are dead, or are predicable. */ - if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ, 0)) - return FALSE; - - /* Conversion went ok, including moving the insns and fixing up the - jump. Adjust the CFG to match. */ - - df_set_bb_dirty (test_bb); - df_set_bb_dirty (then_bb); - delete_basic_block (else_bb); - - num_true_changes++; - num_updated_if_blocks++; - - /* ??? We may now fallthru from one of THEN's successors into a join - block. Rerun cleanup_cfg? Examine things manually? Wait? */ - - return TRUE; -} - -/* Used by the code above to perform the actual rtl transformations. - Return TRUE if successful. - - TEST_BB is the block containing the conditional branch. MERGE_BB - is the block containing the code to manipulate. DEST_EDGE is an - edge representing a jump to the join block; after the conversion, - TEST_BB should be branching to its destination. - REVERSEP is true if the sense of the branch should be reversed. */ - -static int -dead_or_predicable (basic_block test_bb, basic_block merge_bb, - basic_block other_bb, edge dest_edge, int reversep) -{ - basic_block new_dest = dest_edge->dest; - rtx_insn *head, *end, *jump; - rtx_insn *earliest = NULL; - rtx old_dest; - bitmap merge_set = NULL; - /* Number of pending changes. */ - int n_validated_changes = 0; - rtx new_dest_label = NULL_RTX; - - jump = BB_END (test_bb); - - /* Find the extent of the real code in the merge block. */ - head = BB_HEAD (merge_bb); - end = BB_END (merge_bb); - - while (DEBUG_INSN_P (end) && end != head) - end = PREV_INSN (end); - - /* If merge_bb ends with a tablejump, predicating/moving insn's - into test_bb and then deleting merge_bb will result in the jumptable - that follows merge_bb being removed along with merge_bb and then we - get an unresolved reference to the jumptable. */ - if (tablejump_p (end, NULL, NULL)) - return FALSE; - - if (LABEL_P (head)) - head = NEXT_INSN (head); - while (DEBUG_INSN_P (head) && head != end) - head = NEXT_INSN (head); - if (NOTE_P (head)) - { - if (head == end) - { - head = end = NULL; - goto no_body; - } - head = NEXT_INSN (head); - while (DEBUG_INSN_P (head) && head != end) - head = NEXT_INSN (head); - } - - if (JUMP_P (end)) - { - if (!onlyjump_p (end)) - return FALSE; - if (head == end) - { - head = end = NULL; - goto no_body; - } - end = PREV_INSN (end); - while (DEBUG_INSN_P (end) && end != head) - end = PREV_INSN (end); - } - - /* Don't move frame-related insn across the conditional branch. This - can lead to one of the paths of the branch having wrong unwind info. */ - if (epilogue_completed) - { - rtx_insn *insn = head; - while (1) - { - if (INSN_P (insn) && RTX_FRAME_RELATED_P (insn)) - return FALSE; - if (insn == end) - break; - insn = NEXT_INSN (insn); - } - } - - /* Disable handling dead code by conditional execution if the machine needs - to do anything funny with the tests, etc. */ -#ifndef IFCVT_MODIFY_TESTS - if (targetm.have_conditional_execution ()) - { - /* In the conditional execution case, we have things easy. We know - the condition is reversible. We don't have to check life info - because we're going to conditionally execute the code anyway. - All that's left is making sure the insns involved can actually - be predicated. */ - - rtx cond; - - /* If the conditional jump is more than just a conditional jump, - then we cannot do conditional execution conversion on this block. */ - if (!onlyjump_p (jump)) - goto nce; - - cond = cond_exec_get_condition (jump); - if (! cond) - goto nce; - - rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX); - profile_probability prob_val - = (note ? profile_probability::from_reg_br_prob_note (XINT (note, 0)) - : profile_probability::uninitialized ()); - - if (reversep) - { - enum rtx_code rev = reversed_comparison_code (cond, jump); - if (rev == UNKNOWN) - return FALSE; - cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0), - XEXP (cond, 1)); - prob_val = prob_val.invert (); - } - - if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0) - && verify_changes (0)) - n_validated_changes = num_validated_changes (); - else - cancel_changes (0); - - earliest = jump; - } - nce: -#endif - - /* If we allocated new pseudos (e.g. in the conditional move - expander called from noce_emit_cmove), we must resize the - array first. */ - if (max_regno < max_reg_num ()) - max_regno = max_reg_num (); - - /* Try the NCE path if the CE path did not result in any changes. */ - if (n_validated_changes == 0) - { - rtx cond; - rtx_insn *insn; - regset live; - bool success; - - /* In the non-conditional execution case, we have to verify that there - are no trapping operations, no calls, no references to memory, and - that any registers modified are dead at the branch site. */ - - if (!any_condjump_p (jump)) - return FALSE; - - /* Find the extent of the conditional. */ - cond = noce_get_condition (jump, &earliest, false); - if (!cond) - return FALSE; - - live = BITMAP_ALLOC (®_obstack); - simulate_backwards_to_point (merge_bb, live, end); - success = can_move_insns_across (head, end, earliest, jump, - merge_bb, live, - df_get_live_in (other_bb), NULL); - BITMAP_FREE (live); - if (!success) - return FALSE; - - /* Collect the set of registers set in MERGE_BB. */ - merge_set = BITMAP_ALLOC (®_obstack); - - FOR_BB_INSNS (merge_bb, insn) - if (NONDEBUG_INSN_P (insn)) - df_simulate_find_defs (insn, merge_set); - - /* If shrink-wrapping, disable this optimization when test_bb is - the first basic block and merge_bb exits. The idea is to not - move code setting up a return register as that may clobber a - register used to pass function parameters, which then must be - saved in caller-saved regs. A caller-saved reg requires the - prologue, killing a shrink-wrap opportunity. */ - if ((SHRINK_WRAPPING_ENABLED && !epilogue_completed) - && ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == test_bb - && single_succ_p (new_dest) - && single_succ (new_dest) == EXIT_BLOCK_PTR_FOR_FN (cfun) - && bitmap_intersect_p (df_get_live_in (new_dest), merge_set)) - { - regset return_regs; - unsigned int i; - - return_regs = BITMAP_ALLOC (®_obstack); - - /* Start off with the intersection of regs used to pass - params and regs used to return values. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (FUNCTION_ARG_REGNO_P (i) - && targetm.calls.function_value_regno_p (i)) - bitmap_set_bit (return_regs, INCOMING_REGNO (i)); - - bitmap_and_into (return_regs, - df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - bitmap_and_into (return_regs, - df_get_live_in (EXIT_BLOCK_PTR_FOR_FN (cfun))); - if (!bitmap_empty_p (return_regs)) - { - FOR_BB_INSNS_REVERSE (new_dest, insn) - if (NONDEBUG_INSN_P (insn)) - { - df_ref def; - - /* If this insn sets any reg in return_regs, add all - reg uses to the set of regs we're interested in. */ - FOR_EACH_INSN_DEF (def, insn) - if (bitmap_bit_p (return_regs, DF_REF_REGNO (def))) - { - df_simulate_uses (insn, return_regs); - break; - } - } - if (bitmap_intersect_p (merge_set, return_regs)) - { - BITMAP_FREE (return_regs); - BITMAP_FREE (merge_set); - return FALSE; - } - } - BITMAP_FREE (return_regs); - } - } - - no_body: - /* We don't want to use normal invert_jump or redirect_jump because - we don't want to delete_insn called. Also, we want to do our own - change group management. */ - - old_dest = JUMP_LABEL (jump); - if (other_bb != new_dest) - { - if (!any_condjump_p (jump)) - goto cancel; - - if (JUMP_P (BB_END (dest_edge->src))) - new_dest_label = JUMP_LABEL (BB_END (dest_edge->src)); - else if (new_dest == EXIT_BLOCK_PTR_FOR_FN (cfun)) - new_dest_label = ret_rtx; - else - new_dest_label = block_label (new_dest); - - rtx_jump_insn *jump_insn = as_a <rtx_jump_insn *> (jump); - if (reversep - ? ! invert_jump_1 (jump_insn, new_dest_label) - : ! redirect_jump_1 (jump_insn, new_dest_label)) - goto cancel; - } - - if (verify_changes (n_validated_changes)) - confirm_change_group (); - else - goto cancel; - - if (other_bb != new_dest) - { - redirect_jump_2 (as_a <rtx_jump_insn *> (jump), old_dest, new_dest_label, - 0, reversep); - - redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest); - if (reversep) - { - std::swap (BRANCH_EDGE (test_bb)->probability, - FALLTHRU_EDGE (test_bb)->probability); - update_br_prob_note (test_bb); - } - } - - /* Move the insns out of MERGE_BB to before the branch. */ - if (head != NULL) - { - rtx_insn *insn; - - if (end == BB_END (merge_bb)) - BB_END (merge_bb) = PREV_INSN (head); - - /* PR 21767: when moving insns above a conditional branch, the REG_EQUAL - notes being moved might become invalid. */ - insn = head; - do - { - rtx note; - - if (! INSN_P (insn)) - continue; - note = find_reg_note (insn, REG_EQUAL, NULL_RTX); - if (! note) - continue; - remove_note (insn, note); - } while (insn != end && (insn = NEXT_INSN (insn))); - - /* PR46315: when moving insns above a conditional branch, the REG_EQUAL - notes referring to the registers being set might become invalid. */ - if (merge_set) - { - unsigned i; - bitmap_iterator bi; - - EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi) - remove_reg_equal_equiv_notes_for_regno (i); - - BITMAP_FREE (merge_set); - } - - reorder_insns (head, end, PREV_INSN (earliest)); - } - - /* Remove the jump and edge if we can. */ - if (other_bb == new_dest) - { - delete_insn (jump); - remove_edge (BRANCH_EDGE (test_bb)); - /* ??? Can't merge blocks here, as then_bb is still in use. - At minimum, the merge will get done just before bb-reorder. */ - } - - return TRUE; - - cancel: - cancel_changes (0); - - if (merge_set) - BITMAP_FREE (merge_set); - - return FALSE; -} - -/* Main entry point for all if-conversion. AFTER_COMBINE is true if - we are after combine pass. */ - -static void -if_convert (bool after_combine) -{ - basic_block bb; - int pass; - - if (optimize == 1) - { - df_live_add_problem (); - df_live_set_all_dirty (); - } - - /* Record whether we are after combine pass. */ - ifcvt_after_combine = after_combine; - have_cbranchcc4 = (direct_optab_handler (cbranch_optab, CCmode) - != CODE_FOR_nothing); - num_possible_if_blocks = 0; - num_updated_if_blocks = 0; - num_true_changes = 0; - - loop_optimizer_init (AVOID_CFG_MODIFICATIONS); - mark_loop_exit_edges (); - loop_optimizer_finalize (); - free_dominance_info (CDI_DOMINATORS); - - /* Compute postdominators. */ - calculate_dominance_info (CDI_POST_DOMINATORS); - - df_set_flags (DF_LR_RUN_DCE); - - /* Go through each of the basic blocks looking for things to convert. If we - have conditional execution, we make multiple passes to allow us to handle - IF-THEN{-ELSE} blocks within other IF-THEN{-ELSE} blocks. */ - pass = 0; - do - { - df_analyze (); - /* Only need to do dce on the first pass. */ - df_clear_flags (DF_LR_RUN_DCE); - cond_exec_changed_p = FALSE; - pass++; - -#ifdef IFCVT_MULTIPLE_DUMPS - if (dump_file && pass > 1) - fprintf (dump_file, "\n\n========== Pass %d ==========\n", pass); -#endif - - FOR_EACH_BB_FN (bb, cfun) - { - basic_block new_bb; - while (!df_get_bb_dirty (bb) - && (new_bb = find_if_header (bb, pass)) != NULL) - bb = new_bb; - } - -#ifdef IFCVT_MULTIPLE_DUMPS - if (dump_file && cond_exec_changed_p) - print_rtl_with_bb (dump_file, get_insns (), dump_flags); -#endif - } - while (cond_exec_changed_p); - -#ifdef IFCVT_MULTIPLE_DUMPS - if (dump_file) - fprintf (dump_file, "\n\n========== no more changes\n"); -#endif - - free_dominance_info (CDI_POST_DOMINATORS); - - if (dump_file) - fflush (dump_file); - - clear_aux_for_blocks (); - - /* If we allocated new pseudos, we must resize the array for sched1. */ - if (max_regno < max_reg_num ()) - max_regno = max_reg_num (); - - /* Write the final stats. */ - if (dump_file && num_possible_if_blocks > 0) - { - fprintf (dump_file, - "\n%d possible IF blocks searched.\n", - num_possible_if_blocks); - fprintf (dump_file, - "%d IF blocks converted.\n", - num_updated_if_blocks); - fprintf (dump_file, - "%d true changes made.\n\n\n", - num_true_changes); - } - - if (optimize == 1) - df_remove_problem (df_live); - - /* Some non-cold blocks may now be only reachable from cold blocks. - Fix that up. */ - fixup_partitions (); - - checking_verify_flow_info (); -} - -/* If-conversion and CFG cleanup. */ -static unsigned int -rest_of_handle_if_conversion (void) -{ - int flags = 0; - - if (flag_if_conversion) - { - if (dump_file) - { - dump_reg_info (dump_file); - dump_flow_info (dump_file, dump_flags); - } - cleanup_cfg (CLEANUP_EXPENSIVE); - if_convert (false); - if (num_updated_if_blocks) - /* Get rid of any dead CC-related instructions. */ - flags |= CLEANUP_FORCE_FAST_DCE; - } - - cleanup_cfg (flags); - return 0; -} - -namespace { - -const pass_data pass_data_rtl_ifcvt = -{ - RTL_PASS, /* type */ - "ce1", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_IFCVT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; - -class pass_rtl_ifcvt : public rtl_opt_pass -{ -public: - pass_rtl_ifcvt (gcc::context *ctxt) - : rtl_opt_pass (pass_data_rtl_ifcvt, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) - { - return (optimize > 0) && dbg_cnt (if_conversion); - } - - virtual unsigned int execute (function *) - { - return rest_of_handle_if_conversion (); - } - -}; // class pass_rtl_ifcvt - -} // anon namespace - -rtl_opt_pass * -make_pass_rtl_ifcvt (gcc::context *ctxt) -{ - return new pass_rtl_ifcvt (ctxt); -} - - -/* Rerun if-conversion, as combine may have simplified things enough - to now meet sequence length restrictions. */ - -namespace { - -const pass_data pass_data_if_after_combine = -{ - RTL_PASS, /* type */ - "ce2", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_IFCVT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; - -class pass_if_after_combine : public rtl_opt_pass -{ -public: - pass_if_after_combine (gcc::context *ctxt) - : rtl_opt_pass (pass_data_if_after_combine, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) - { - return optimize > 0 && flag_if_conversion - && dbg_cnt (if_after_combine); - } - - virtual unsigned int execute (function *) - { - if_convert (true); - return 0; - } - -}; // class pass_if_after_combine - -} // anon namespace - -rtl_opt_pass * -make_pass_if_after_combine (gcc::context *ctxt) -{ - return new pass_if_after_combine (ctxt); -} - - -namespace { - -const pass_data pass_data_if_after_reload = -{ - RTL_PASS, /* type */ - "ce3", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_IFCVT2, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; - -class pass_if_after_reload : public rtl_opt_pass -{ -public: - pass_if_after_reload (gcc::context *ctxt) - : rtl_opt_pass (pass_data_if_after_reload, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) - { - return optimize > 0 && flag_if_conversion2 - && dbg_cnt (if_after_reload); - } - - virtual unsigned int execute (function *) - { - if_convert (true); - return 0; - } - -}; // class pass_if_after_reload - -} // anon namespace - -rtl_opt_pass * -make_pass_if_after_reload (gcc::context *ctxt) -{ - return new pass_if_after_reload (ctxt); -} |