aboutsummaryrefslogtreecommitdiff
path: root/gcc/ifcvt.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/ifcvt.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/ifcvt.c')
-rw-r--r--gcc/ifcvt.c5694
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, &REG_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 (&reg_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 (&reg_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 (&reg_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 (&reg_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 (&reg_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);
-}