aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.cc
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/combine.cc
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/combine.cc')
-rw-r--r--gcc/combine.cc14960
1 files changed, 14960 insertions, 0 deletions
diff --git a/gcc/combine.cc b/gcc/combine.cc
new file mode 100644
index 0000000..fb4a27a
--- /dev/null
+++ b/gcc/combine.cc
@@ -0,0 +1,14960 @@
+/* Optimize by combining instructions for GNU compiler.
+ Copyright (C) 1987-2022 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* This module is essentially the "combiner" phase of the U. of Arizona
+ Portable Optimizer, but redone to work on our list-structured
+ representation for RTL instead of their string representation.
+
+ The LOG_LINKS of each insn identify the most recent assignment
+ to each REG used in the insn. It is a list of previous insns,
+ each of which contains a SET for a REG that is used in this insn
+ and not used or set in between. LOG_LINKs never cross basic blocks.
+ They were set up by the preceding pass (lifetime analysis).
+
+ We try to combine each pair of insns joined by a logical link.
+ We also try to combine triplets of insns A, B and C when C has
+ a link back to B and B has a link back to A. Likewise for a
+ small number of quadruplets of insns A, B, C and D for which
+ there's high likelihood of success.
+
+ We check (with modified_between_p) to avoid combining in such a way
+ as to move a computation to a place where its value would be different.
+
+ Combination is done by mathematically substituting the previous
+ insn(s) values for the regs they set into the expressions in
+ the later insns that refer to these regs. If the result is a valid insn
+ for our target machine, according to the machine description,
+ we install it, delete the earlier insns, and update the data flow
+ information (LOG_LINKS and REG_NOTES) for what we did.
+
+ There are a few exceptions where the dataflow information isn't
+ completely updated (however this is only a local issue since it is
+ regenerated before the next pass that uses it):
+
+ - reg_live_length is not updated
+ - reg_n_refs is not adjusted in the rare case when a register is
+ no longer required in a computation
+ - there are extremely rare cases (see distribute_notes) when a
+ REG_DEAD note is lost
+ - a LOG_LINKS entry that refers to an insn with multiple SETs may be
+ removed because there is no way to know which register it was
+ linking
+
+ To simplify substitution, we combine only when the earlier insn(s)
+ consist of only a single assignment. To simplify updating afterward,
+ we never combine when a subroutine call appears in the middle. */
+
+#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 "predict.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "cgraph.h"
+#include "stor-layout.h"
+#include "cfgrtl.h"
+#include "cfgcleanup.h"
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+#include "explow.h"
+#include "insn-attr.h"
+#include "rtlhooks-def.h"
+#include "expr.h"
+#include "tree-pass.h"
+#include "valtrack.h"
+#include "rtl-iter.h"
+#include "print-rtl.h"
+#include "function-abi.h"
+#include "rtlanal.h"
+
+/* Number of attempts to combine instructions in this function. */
+
+static int combine_attempts;
+
+/* Number of attempts that got as far as substitution in this function. */
+
+static int combine_merges;
+
+/* Number of instructions combined with added SETs in this function. */
+
+static int combine_extras;
+
+/* Number of instructions combined in this function. */
+
+static int combine_successes;
+
+/* Totals over entire compilation. */
+
+static int total_attempts, total_merges, total_extras, total_successes;
+
+/* combine_instructions may try to replace the right hand side of the
+ second instruction with the value of an associated REG_EQUAL note
+ before throwing it at try_combine. That is problematic when there
+ is a REG_DEAD note for a register used in the old right hand side
+ and can cause distribute_notes to do wrong things. This is the
+ second instruction if it has been so modified, null otherwise. */
+
+static rtx_insn *i2mod;
+
+/* When I2MOD is nonnull, this is a copy of the old right hand side. */
+
+static rtx i2mod_old_rhs;
+
+/* When I2MOD is nonnull, this is a copy of the new right hand side. */
+
+static rtx i2mod_new_rhs;
+
+struct reg_stat_type {
+ /* Record last point of death of (hard or pseudo) register n. */
+ rtx_insn *last_death;
+
+ /* Record last point of modification of (hard or pseudo) register n. */
+ rtx_insn *last_set;
+
+ /* The next group of fields allows the recording of the last value assigned
+ to (hard or pseudo) register n. We use this information to see if an
+ operation being processed is redundant given a prior operation performed
+ on the register. For example, an `and' with a constant is redundant if
+ all the zero bits are already known to be turned off.
+
+ We use an approach similar to that used by cse, but change it in the
+ following ways:
+
+ (1) We do not want to reinitialize at each label.
+ (2) It is useful, but not critical, to know the actual value assigned
+ to a register. Often just its form is helpful.
+
+ Therefore, we maintain the following fields:
+
+ last_set_value the last value assigned
+ last_set_label records the value of label_tick when the
+ register was assigned
+ last_set_table_tick records the value of label_tick when a
+ value using the register is assigned
+ last_set_invalid set to nonzero when it is not valid
+ to use the value of this register in some
+ register's value
+
+ To understand the usage of these tables, it is important to understand
+ the distinction between the value in last_set_value being valid and
+ the register being validly contained in some other expression in the
+ table.
+
+ (The next two parameters are out of date).
+
+ reg_stat[i].last_set_value is valid if it is nonzero, and either
+ reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick.
+
+ Register I may validly appear in any expression returned for the value
+ of another register if reg_n_sets[i] is 1. It may also appear in the
+ value for register J if reg_stat[j].last_set_invalid is zero, or
+ reg_stat[i].last_set_label < reg_stat[j].last_set_label.
+
+ If an expression is found in the table containing a register which may
+ not validly appear in an expression, the register is replaced by
+ something that won't match, (clobber (const_int 0)). */
+
+ /* Record last value assigned to (hard or pseudo) register n. */
+
+ rtx last_set_value;
+
+ /* Record the value of label_tick when an expression involving register n
+ is placed in last_set_value. */
+
+ int last_set_table_tick;
+
+ /* Record the value of label_tick when the value for register n is placed in
+ last_set_value. */
+
+ int last_set_label;
+
+ /* These fields are maintained in parallel with last_set_value and are
+ used to store the mode in which the register was last set, the bits
+ that were known to be zero when it was last set, and the number of
+ sign bits copies it was known to have when it was last set. */
+
+ unsigned HOST_WIDE_INT last_set_nonzero_bits;
+ char last_set_sign_bit_copies;
+ ENUM_BITFIELD(machine_mode) last_set_mode : 8;
+
+ /* Set nonzero if references to register n in expressions should not be
+ used. last_set_invalid is set nonzero when this register is being
+ assigned to and last_set_table_tick == label_tick. */
+
+ char last_set_invalid;
+
+ /* Some registers that are set more than once and used in more than one
+ basic block are nevertheless always set in similar ways. For example,
+ a QImode register may be loaded from memory in two places on a machine
+ where byte loads zero extend.
+
+ We record in the following fields if a register has some leading bits
+ that are always equal to the sign bit, and what we know about the
+ nonzero bits of a register, specifically which bits are known to be
+ zero.
+
+ If an entry is zero, it means that we don't know anything special. */
+
+ unsigned char sign_bit_copies;
+
+ unsigned HOST_WIDE_INT nonzero_bits;
+
+ /* Record the value of the label_tick when the last truncation
+ happened. The field truncated_to_mode is only valid if
+ truncation_label == label_tick. */
+
+ int truncation_label;
+
+ /* Record the last truncation seen for this register. If truncation
+ is not a nop to this mode we might be able to save an explicit
+ truncation if we know that value already contains a truncated
+ value. */
+
+ ENUM_BITFIELD(machine_mode) truncated_to_mode : 8;
+};
+
+
+static vec<reg_stat_type> reg_stat;
+
+/* One plus the highest pseudo for which we track REG_N_SETS.
+ regstat_init_n_sets_and_refs allocates the array for REG_N_SETS just once,
+ but during combine_split_insns new pseudos can be created. As we don't have
+ updated DF information in that case, it is hard to initialize the array
+ after growing. The combiner only cares about REG_N_SETS (regno) == 1,
+ so instead of growing the arrays, just assume all newly created pseudos
+ during combine might be set multiple times. */
+
+static unsigned int reg_n_sets_max;
+
+/* Record the luid of the last insn that invalidated memory
+ (anything that writes memory, and subroutine calls, but not pushes). */
+
+static int mem_last_set;
+
+/* Record the luid of the last CALL_INSN
+ so we can tell whether a potential combination crosses any calls. */
+
+static int last_call_luid;
+
+/* When `subst' is called, this is the insn that is being modified
+ (by combining in a previous insn). The PATTERN of this insn
+ is still the old pattern partially modified and it should not be
+ looked at, but this may be used to examine the successors of the insn
+ to judge whether a simplification is valid. */
+
+static rtx_insn *subst_insn;
+
+/* This is the lowest LUID that `subst' is currently dealing with.
+ get_last_value will not return a value if the register was set at or
+ after this LUID. If not for this mechanism, we could get confused if
+ I2 or I1 in try_combine were an insn that used the old value of a register
+ to obtain a new value. In that case, we might erroneously get the
+ new value of the register when we wanted the old one. */
+
+static int subst_low_luid;
+
+/* This contains any hard registers that are used in newpat; reg_dead_at_p
+ must consider all these registers to be always live. */
+
+static HARD_REG_SET newpat_used_regs;
+
+/* This is an insn to which a LOG_LINKS entry has been added. If this
+ insn is the earlier than I2 or I3, combine should rescan starting at
+ that location. */
+
+static rtx_insn *added_links_insn;
+
+/* And similarly, for notes. */
+
+static rtx_insn *added_notes_insn;
+
+/* Basic block in which we are performing combines. */
+static basic_block this_basic_block;
+static bool optimize_this_for_speed_p;
+
+
+/* Length of the currently allocated uid_insn_cost array. */
+
+static int max_uid_known;
+
+/* The following array records the insn_cost for every insn
+ in the instruction stream. */
+
+static int *uid_insn_cost;
+
+/* The following array records the LOG_LINKS for every insn in the
+ instruction stream as struct insn_link pointers. */
+
+struct insn_link {
+ rtx_insn *insn;
+ unsigned int regno;
+ struct insn_link *next;
+};
+
+static struct insn_link **uid_log_links;
+
+static inline int
+insn_uid_check (const_rtx insn)
+{
+ int uid = INSN_UID (insn);
+ gcc_checking_assert (uid <= max_uid_known);
+ return uid;
+}
+
+#define INSN_COST(INSN) (uid_insn_cost[insn_uid_check (INSN)])
+#define LOG_LINKS(INSN) (uid_log_links[insn_uid_check (INSN)])
+
+#define FOR_EACH_LOG_LINK(L, INSN) \
+ for ((L) = LOG_LINKS (INSN); (L); (L) = (L)->next)
+
+/* Links for LOG_LINKS are allocated from this obstack. */
+
+static struct obstack insn_link_obstack;
+
+/* Allocate a link. */
+
+static inline struct insn_link *
+alloc_insn_link (rtx_insn *insn, unsigned int regno, struct insn_link *next)
+{
+ struct insn_link *l
+ = (struct insn_link *) obstack_alloc (&insn_link_obstack,
+ sizeof (struct insn_link));
+ l->insn = insn;
+ l->regno = regno;
+ l->next = next;
+ return l;
+}
+
+/* Incremented for each basic block. */
+
+static int label_tick;
+
+/* Reset to label_tick for each extended basic block in scanning order. */
+
+static int label_tick_ebb_start;
+
+/* Mode used to compute significance in reg_stat[].nonzero_bits. It is the
+ largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
+
+static scalar_int_mode nonzero_bits_mode;
+
+/* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
+ be safely used. It is zero while computing them and after combine has
+ completed. This former test prevents propagating values based on
+ previously set values, which can be incorrect if a variable is modified
+ in a loop. */
+
+static int nonzero_sign_valid;
+
+
+/* Record one modification to rtl structure
+ to be undone by storing old_contents into *where. */
+
+enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE, UNDO_LINKS };
+
+struct undo
+{
+ struct undo *next;
+ enum undo_kind kind;
+ union { rtx r; int i; machine_mode m; struct insn_link *l; } old_contents;
+ union { rtx *r; int *i; struct insn_link **l; } where;
+};
+
+/* Record a bunch of changes to be undone, up to MAX_UNDO of them.
+ num_undo says how many are currently recorded.
+
+ other_insn is nonzero if we have modified some other insn in the process
+ of working on subst_insn. It must be verified too. */
+
+struct undobuf
+{
+ struct undo *undos;
+ struct undo *frees;
+ rtx_insn *other_insn;
+};
+
+static struct undobuf undobuf;
+
+/* Number of times the pseudo being substituted for
+ was found and replaced. */
+
+static int n_occurrences;
+
+static rtx reg_nonzero_bits_for_combine (const_rtx, scalar_int_mode,
+ scalar_int_mode,
+ unsigned HOST_WIDE_INT *);
+static rtx reg_num_sign_bit_copies_for_combine (const_rtx, scalar_int_mode,
+ scalar_int_mode,
+ unsigned int *);
+static void do_SUBST (rtx *, rtx);
+static void do_SUBST_INT (int *, int);
+static void init_reg_last (void);
+static void setup_incoming_promotions (rtx_insn *);
+static void set_nonzero_bits_and_sign_copies (rtx, const_rtx, void *);
+static int cant_combine_insn_p (rtx_insn *);
+static int can_combine_p (rtx_insn *, rtx_insn *, rtx_insn *, rtx_insn *,
+ rtx_insn *, rtx_insn *, rtx *, rtx *);
+static int combinable_i3pat (rtx_insn *, rtx *, rtx, rtx, rtx, int, int, rtx *);
+static int contains_muldiv (rtx);
+static rtx_insn *try_combine (rtx_insn *, rtx_insn *, rtx_insn *, rtx_insn *,
+ int *, rtx_insn *);
+static void undo_all (void);
+static void undo_commit (void);
+static rtx *find_split_point (rtx *, rtx_insn *, bool);
+static rtx subst (rtx, rtx, rtx, int, int, int);
+static rtx combine_simplify_rtx (rtx, machine_mode, int, int);
+static rtx simplify_if_then_else (rtx);
+static rtx simplify_set (rtx);
+static rtx simplify_logical (rtx);
+static rtx expand_compound_operation (rtx);
+static const_rtx expand_field_assignment (const_rtx);
+static rtx make_extraction (machine_mode, rtx, HOST_WIDE_INT,
+ rtx, unsigned HOST_WIDE_INT, int, int, int);
+static int get_pos_from_mask (unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT *);
+static rtx canon_reg_for_combine (rtx, rtx);
+static rtx force_int_to_mode (rtx, scalar_int_mode, scalar_int_mode,
+ scalar_int_mode, unsigned HOST_WIDE_INT, int);
+static rtx force_to_mode (rtx, machine_mode,
+ unsigned HOST_WIDE_INT, int);
+static rtx if_then_else_cond (rtx, rtx *, rtx *);
+static rtx known_cond (rtx, enum rtx_code, rtx, rtx);
+static int rtx_equal_for_field_assignment_p (rtx, rtx, bool = false);
+static rtx make_field_assignment (rtx);
+static rtx apply_distributive_law (rtx);
+static rtx distribute_and_simplify_rtx (rtx, int);
+static rtx simplify_and_const_int_1 (scalar_int_mode, rtx,
+ unsigned HOST_WIDE_INT);
+static rtx simplify_and_const_int (rtx, scalar_int_mode, rtx,
+ unsigned HOST_WIDE_INT);
+static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
+ HOST_WIDE_INT, machine_mode, int *);
+static rtx simplify_shift_const_1 (enum rtx_code, machine_mode, rtx, int);
+static rtx simplify_shift_const (rtx, enum rtx_code, machine_mode, rtx,
+ int);
+static int recog_for_combine (rtx *, rtx_insn *, rtx *);
+static rtx gen_lowpart_for_combine (machine_mode, rtx);
+static enum rtx_code simplify_compare_const (enum rtx_code, machine_mode,
+ rtx, rtx *);
+static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
+static void update_table_tick (rtx);
+static void record_value_for_reg (rtx, rtx_insn *, rtx);
+static void check_promoted_subreg (rtx_insn *, rtx);
+static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
+static void record_dead_and_set_regs (rtx_insn *);
+static int get_last_value_validate (rtx *, rtx_insn *, int, int);
+static rtx get_last_value (const_rtx);
+static void reg_dead_at_p_1 (rtx, const_rtx, void *);
+static int reg_dead_at_p (rtx, rtx_insn *);
+static void move_deaths (rtx, rtx, int, rtx_insn *, rtx *);
+static int reg_bitfield_target_p (rtx, rtx);
+static void distribute_notes (rtx, rtx_insn *, rtx_insn *, rtx_insn *, rtx, rtx, rtx);
+static void distribute_links (struct insn_link *);
+static void mark_used_regs_combine (rtx);
+static void record_promoted_value (rtx_insn *, rtx);
+static bool unmentioned_reg_p (rtx, rtx);
+static void record_truncated_values (rtx *, void *);
+static bool reg_truncated_to_mode (machine_mode, const_rtx);
+static rtx gen_lowpart_or_truncate (machine_mode, rtx);
+
+
+/* It is not safe to use ordinary gen_lowpart in combine.
+ See comments in gen_lowpart_for_combine. */
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine
+
+/* Our implementation of gen_lowpart never emits a new pseudo. */
+#undef RTL_HOOKS_GEN_LOWPART_NO_EMIT
+#define RTL_HOOKS_GEN_LOWPART_NO_EMIT gen_lowpart_for_combine
+
+#undef RTL_HOOKS_REG_NONZERO_REG_BITS
+#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine
+
+#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES
+#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine
+
+#undef RTL_HOOKS_REG_TRUNCATED_TO_MODE
+#define RTL_HOOKS_REG_TRUNCATED_TO_MODE reg_truncated_to_mode
+
+static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
+
+
+/* Convenience wrapper for the canonicalize_comparison target hook.
+ Target hooks cannot use enum rtx_code. */
+static inline void
+target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ int code_int = (int)*code;
+ targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
+ *code = (enum rtx_code)code_int;
+}
+
+/* Try to split PATTERN found in INSN. This returns NULL_RTX if
+ PATTERN cannot be split. Otherwise, it returns an insn sequence.
+ This is a wrapper around split_insns which ensures that the
+ reg_stat vector is made larger if the splitter creates a new
+ register. */
+
+static rtx_insn *
+combine_split_insns (rtx pattern, rtx_insn *insn)
+{
+ rtx_insn *ret;
+ unsigned int nregs;
+
+ ret = split_insns (pattern, insn);
+ nregs = max_reg_num ();
+ if (nregs > reg_stat.length ())
+ reg_stat.safe_grow_cleared (nregs, true);
+ return ret;
+}
+
+/* This is used by find_single_use to locate an rtx in LOC that
+ contains exactly one use of DEST, which is typically a REG.
+ It returns a pointer to the innermost rtx expression
+ containing DEST. Appearances of DEST that are being used to
+ totally replace it are not counted. */
+
+static rtx *
+find_single_use_1 (rtx dest, rtx *loc)
+{
+ rtx x = *loc;
+ enum rtx_code code = GET_CODE (x);
+ rtx *result = NULL;
+ rtx *this_result;
+ int i;
+ const char *fmt;
+
+ switch (code)
+ {
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ CASE_CONST_ANY:
+ case CLOBBER:
+ return 0;
+
+ case SET:
+ /* If the destination is anything other than PC, a REG or a SUBREG
+ of a REG that occupies all of the REG, the insn uses DEST if
+ it is mentioned in the destination or the source. Otherwise, we
+ need just check the source. */
+ if (GET_CODE (SET_DEST (x)) != PC
+ && !REG_P (SET_DEST (x))
+ && ! (GET_CODE (SET_DEST (x)) == SUBREG
+ && REG_P (SUBREG_REG (SET_DEST (x)))
+ && !read_modify_subreg_p (SET_DEST (x))))
+ break;
+
+ return find_single_use_1 (dest, &SET_SRC (x));
+
+ case MEM:
+ case SUBREG:
+ return find_single_use_1 (dest, &XEXP (x, 0));
+
+ default:
+ break;
+ }
+
+ /* If it wasn't one of the common cases above, check each expression and
+ vector of this code. Look for a unique usage of DEST. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (dest == XEXP (x, i)
+ || (REG_P (dest) && REG_P (XEXP (x, i))
+ && REGNO (dest) == REGNO (XEXP (x, i))))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XEXP (x, i));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ /* Duplicate usage. */
+ return NULL;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (XVECEXP (x, i, j) == dest
+ || (REG_P (dest)
+ && REG_P (XVECEXP (x, i, j))
+ && REGNO (XVECEXP (x, i, j)) == REGNO (dest)))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XVECEXP (x, i, j));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ return NULL;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* See if DEST, produced in INSN, is used only a single time in the
+ sequel. If so, return a pointer to the innermost rtx expression in which
+ it is used.
+
+ If PLOC is nonzero, *PLOC is set to the insn containing the single use.
+
+ Otherwise, we find the single use by finding an insn that has a
+ LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is
+ only referenced once in that insn, we know that it must be the first
+ and last insn referencing DEST. */
+
+static rtx *
+find_single_use (rtx dest, rtx_insn *insn, rtx_insn **ploc)
+{
+ basic_block bb;
+ rtx_insn *next;
+ rtx *result;
+ struct insn_link *link;
+
+ if (!REG_P (dest))
+ return 0;
+
+ bb = BLOCK_FOR_INSN (insn);
+ for (next = NEXT_INSN (insn);
+ next && BLOCK_FOR_INSN (next) == bb;
+ next = NEXT_INSN (next))
+ if (NONDEBUG_INSN_P (next) && dead_or_set_p (next, dest))
+ {
+ FOR_EACH_LOG_LINK (link, next)
+ if (link->insn == insn && link->regno == REGNO (dest))
+ break;
+
+ if (link)
+ {
+ result = find_single_use_1 (dest, &PATTERN (next));
+ if (ploc)
+ *ploc = next;
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+/* Substitute NEWVAL, an rtx expression, into INTO, a place in some
+ insn. The substitution can be undone by undo_all. If INTO is already
+ set to NEWVAL, do not record this change. Because computing NEWVAL might
+ also call SUBST, we have to compute it before we put anything into
+ the undo table. */
+
+static void
+do_SUBST (rtx *into, rtx newval)
+{
+ struct undo *buf;
+ rtx oldval = *into;
+
+ if (oldval == newval)
+ return;
+
+ /* We'd like to catch as many invalid transformations here as
+ possible. Unfortunately, there are way too many mode changes
+ that are perfectly valid, so we'd waste too much effort for
+ little gain doing the checks here. Focus on catching invalid
+ transformations involving integer constants. */
+ if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
+ && CONST_INT_P (newval))
+ {
+ /* Sanity check that we're replacing oldval with a CONST_INT
+ that is a valid sign-extension for the original mode. */
+ gcc_assert (INTVAL (newval)
+ == trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval)));
+
+ /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
+ CONST_INT is not valid, because after the replacement, the
+ original mode would be gone. Unfortunately, we can't tell
+ when do_SUBST is called to replace the operand thereof, so we
+ perform this test on oldval instead, checking whether an
+ invalid replacement took place before we got here. */
+ gcc_assert (!(GET_CODE (oldval) == SUBREG
+ && CONST_INT_P (SUBREG_REG (oldval))));
+ gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
+ && CONST_INT_P (XEXP (oldval, 0))));
+ }
+
+ if (undobuf.frees)
+ buf = undobuf.frees, undobuf.frees = buf->next;
+ else
+ buf = XNEW (struct undo);
+
+ buf->kind = UNDO_RTX;
+ buf->where.r = into;
+ buf->old_contents.r = oldval;
+ *into = newval;
+
+ buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST(INTO, NEWVAL) do_SUBST (&(INTO), (NEWVAL))
+
+/* Similar to SUBST, but NEWVAL is an int expression. Note that substitution
+ for the value of a HOST_WIDE_INT value (including CONST_INT) is
+ not safe. */
+
+static void
+do_SUBST_INT (int *into, int newval)
+{
+ struct undo *buf;
+ int oldval = *into;
+
+ if (oldval == newval)
+ return;
+
+ if (undobuf.frees)
+ buf = undobuf.frees, undobuf.frees = buf->next;
+ else
+ buf = XNEW (struct undo);
+
+ buf->kind = UNDO_INT;
+ buf->where.i = into;
+ buf->old_contents.i = oldval;
+ *into = newval;
+
+ buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_INT(INTO, NEWVAL) do_SUBST_INT (&(INTO), (NEWVAL))
+
+/* Similar to SUBST, but just substitute the mode. This is used when
+ changing the mode of a pseudo-register, so that any other
+ references to the entry in the regno_reg_rtx array will change as
+ well. */
+
+static void
+do_SUBST_MODE (rtx *into, machine_mode newval)
+{
+ struct undo *buf;
+ machine_mode oldval = GET_MODE (*into);
+
+ if (oldval == newval)
+ return;
+
+ if (undobuf.frees)
+ buf = undobuf.frees, undobuf.frees = buf->next;
+ else
+ buf = XNEW (struct undo);
+
+ buf->kind = UNDO_MODE;
+ buf->where.r = into;
+ buf->old_contents.m = oldval;
+ adjust_reg_mode (*into, newval);
+
+ buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE (&(INTO), (NEWVAL))
+
+/* Similar to SUBST, but NEWVAL is a LOG_LINKS expression. */
+
+static void
+do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
+{
+ struct undo *buf;
+ struct insn_link * oldval = *into;
+
+ if (oldval == newval)
+ return;
+
+ if (undobuf.frees)
+ buf = undobuf.frees, undobuf.frees = buf->next;
+ else
+ buf = XNEW (struct undo);
+
+ buf->kind = UNDO_LINKS;
+ buf->where.l = into;
+ buf->old_contents.l = oldval;
+ *into = newval;
+
+ buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
+
+/* Subroutine of try_combine. Determine whether the replacement patterns
+ NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_cost
+ than the original sequence I0, I1, I2, I3 and undobuf.other_insn. Note
+ that I0, I1 and/or NEWI2PAT may be NULL_RTX. Similarly, NEWOTHERPAT and
+ undobuf.other_insn may also both be NULL_RTX. Return false if the cost
+ of all the instructions can be estimated and the replacements are more
+ expensive than the original sequence. */
+
+static bool
+combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3,
+ rtx newpat, rtx newi2pat, rtx newotherpat)
+{
+ int i0_cost, i1_cost, i2_cost, i3_cost;
+ int new_i2_cost, new_i3_cost;
+ int old_cost, new_cost;
+
+ /* Lookup the original insn_costs. */
+ i2_cost = INSN_COST (i2);
+ i3_cost = INSN_COST (i3);
+
+ if (i1)
+ {
+ i1_cost = INSN_COST (i1);
+ if (i0)
+ {
+ i0_cost = INSN_COST (i0);
+ old_cost = (i0_cost > 0 && i1_cost > 0 && i2_cost > 0 && i3_cost > 0
+ ? i0_cost + i1_cost + i2_cost + i3_cost : 0);
+ }
+ else
+ {
+ old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0
+ ? i1_cost + i2_cost + i3_cost : 0);
+ i0_cost = 0;
+ }
+ }
+ else
+ {
+ old_cost = (i2_cost > 0 && i3_cost > 0) ? i2_cost + i3_cost : 0;
+ i1_cost = i0_cost = 0;
+ }
+
+ /* If we have split a PARALLEL I2 to I1,I2, we have counted its cost twice;
+ correct that. */
+ if (old_cost && i1 && INSN_UID (i1) == INSN_UID (i2))
+ old_cost -= i1_cost;
+
+
+ /* Calculate the replacement insn_costs. */
+ rtx tmp = PATTERN (i3);
+ PATTERN (i3) = newpat;
+ int tmpi = INSN_CODE (i3);
+ INSN_CODE (i3) = -1;
+ new_i3_cost = insn_cost (i3, optimize_this_for_speed_p);
+ PATTERN (i3) = tmp;
+ INSN_CODE (i3) = tmpi;
+ if (newi2pat)
+ {
+ tmp = PATTERN (i2);
+ PATTERN (i2) = newi2pat;
+ tmpi = INSN_CODE (i2);
+ INSN_CODE (i2) = -1;
+ new_i2_cost = insn_cost (i2, optimize_this_for_speed_p);
+ PATTERN (i2) = tmp;
+ INSN_CODE (i2) = tmpi;
+ new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
+ ? new_i2_cost + new_i3_cost : 0;
+ }
+ else
+ {
+ new_cost = new_i3_cost;
+ new_i2_cost = 0;
+ }
+
+ if (undobuf.other_insn)
+ {
+ int old_other_cost, new_other_cost;
+
+ old_other_cost = INSN_COST (undobuf.other_insn);
+ tmp = PATTERN (undobuf.other_insn);
+ PATTERN (undobuf.other_insn) = newotherpat;
+ tmpi = INSN_CODE (undobuf.other_insn);
+ INSN_CODE (undobuf.other_insn) = -1;
+ new_other_cost = insn_cost (undobuf.other_insn,
+ optimize_this_for_speed_p);
+ PATTERN (undobuf.other_insn) = tmp;
+ INSN_CODE (undobuf.other_insn) = tmpi;
+ if (old_other_cost > 0 && new_other_cost > 0)
+ {
+ old_cost += old_other_cost;
+ new_cost += new_other_cost;
+ }
+ else
+ old_cost = 0;
+ }
+
+ /* Disallow this combination if both new_cost and old_cost are greater than
+ zero, and new_cost is greater than old cost. */
+ int reject = old_cost > 0 && new_cost > old_cost;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "%s combination of insns ",
+ reject ? "rejecting" : "allowing");
+ if (i0)
+ fprintf (dump_file, "%d, ", INSN_UID (i0));
+ if (i1 && INSN_UID (i1) != INSN_UID (i2))
+ fprintf (dump_file, "%d, ", INSN_UID (i1));
+ fprintf (dump_file, "%d and %d\n", INSN_UID (i2), INSN_UID (i3));
+
+ fprintf (dump_file, "original costs ");
+ if (i0)
+ fprintf (dump_file, "%d + ", i0_cost);
+ if (i1 && INSN_UID (i1) != INSN_UID (i2))
+ fprintf (dump_file, "%d + ", i1_cost);
+ fprintf (dump_file, "%d + %d = %d\n", i2_cost, i3_cost, old_cost);
+
+ if (newi2pat)
+ fprintf (dump_file, "replacement costs %d + %d = %d\n",
+ new_i2_cost, new_i3_cost, new_cost);
+ else
+ fprintf (dump_file, "replacement cost %d\n", new_cost);
+ }
+
+ if (reject)
+ return false;
+
+ /* Update the uid_insn_cost array with the replacement costs. */
+ INSN_COST (i2) = new_i2_cost;
+ INSN_COST (i3) = new_i3_cost;
+ if (i1)
+ {
+ INSN_COST (i1) = 0;
+ if (i0)
+ INSN_COST (i0) = 0;
+ }
+
+ return true;
+}
+
+
+/* Delete any insns that copy a register to itself.
+ Return true if the CFG was changed. */
+
+static bool
+delete_noop_moves (void)
+{
+ rtx_insn *insn, *next;
+ basic_block bb;
+
+ bool edges_deleted = false;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (INSN_P (insn) && noop_move_p (insn))
+ {
+ if (dump_file)
+ fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn));
+
+ edges_deleted |= delete_insn_and_edges (insn);
+ }
+ }
+ }
+
+ return edges_deleted;
+}
+
+
+/* Return false if we do not want to (or cannot) combine DEF. */
+static bool
+can_combine_def_p (df_ref def)
+{
+ /* Do not consider if it is pre/post modification in MEM. */
+ if (DF_REF_FLAGS (def) & DF_REF_PRE_POST_MODIFY)
+ return false;
+
+ unsigned int regno = DF_REF_REGNO (def);
+
+ /* Do not combine frame pointer adjustments. */
+ if ((regno == FRAME_POINTER_REGNUM
+ && (!reload_completed || frame_pointer_needed))
+ || (!HARD_FRAME_POINTER_IS_FRAME_POINTER
+ && regno == HARD_FRAME_POINTER_REGNUM
+ && (!reload_completed || frame_pointer_needed))
+ || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && regno == ARG_POINTER_REGNUM && fixed_regs[regno]))
+ return false;
+
+ return true;
+}
+
+/* Return false if we do not want to (or cannot) combine USE. */
+static bool
+can_combine_use_p (df_ref use)
+{
+ /* Do not consider the usage of the stack pointer by function call. */
+ if (DF_REF_FLAGS (use) & DF_REF_CALL_STACK_USAGE)
+ return false;
+
+ return true;
+}
+
+/* Fill in log links field for all insns. */
+
+static void
+create_log_links (void)
+{
+ basic_block bb;
+ rtx_insn **next_use;
+ rtx_insn *insn;
+ df_ref def, use;
+
+ next_use = XCNEWVEC (rtx_insn *, max_reg_num ());
+
+ /* Pass through each block from the end, recording the uses of each
+ register and establishing log links when def is encountered.
+ Note that we do not clear next_use array in order to save time,
+ so we have to test whether the use is in the same basic block as def.
+
+ There are a few cases below when we do not consider the definition or
+ usage -- these are taken from original flow.c did. Don't ask me why it is
+ done this way; I don't know and if it works, I don't want to know. */
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ /* Log links are created only once. */
+ gcc_assert (!LOG_LINKS (insn));
+
+ FOR_EACH_INSN_DEF (def, insn)
+ {
+ unsigned int regno = DF_REF_REGNO (def);
+ rtx_insn *use_insn;
+
+ if (!next_use[regno])
+ continue;
+
+ if (!can_combine_def_p (def))
+ continue;
+
+ use_insn = next_use[regno];
+ next_use[regno] = NULL;
+
+ if (BLOCK_FOR_INSN (use_insn) != bb)
+ continue;
+
+ /* flow.c claimed:
+
+ We don't build a LOG_LINK for hard registers contained
+ in ASM_OPERANDs. If these registers get replaced,
+ we might wind up changing the semantics of the insn,
+ even if reload can make what appear to be valid
+ assignments later. */
+ if (regno < FIRST_PSEUDO_REGISTER
+ && asm_noperands (PATTERN (use_insn)) >= 0)
+ continue;
+
+ /* Don't add duplicate links between instructions. */
+ struct insn_link *links;
+ FOR_EACH_LOG_LINK (links, use_insn)
+ if (insn == links->insn && regno == links->regno)
+ break;
+
+ if (!links)
+ LOG_LINKS (use_insn)
+ = alloc_insn_link (insn, regno, LOG_LINKS (use_insn));
+ }
+
+ FOR_EACH_INSN_USE (use, insn)
+ if (can_combine_use_p (use))
+ next_use[DF_REF_REGNO (use)] = insn;
+ }
+ }
+
+ free (next_use);
+}
+
+/* Walk the LOG_LINKS of insn B to see if we find a reference to A. Return
+ true if we found a LOG_LINK that proves that A feeds B. This only works
+ if there are no instructions between A and B which could have a link
+ depending on A, since in that case we would not record a link for B. */
+
+static bool
+insn_a_feeds_b (rtx_insn *a, rtx_insn *b)
+{
+ struct insn_link *links;
+ FOR_EACH_LOG_LINK (links, b)
+ if (links->insn == a)
+ return true;
+ return false;
+}
+
+/* Main entry point for combiner. F is the first insn of the function.
+ NREGS is the first unused pseudo-reg number.
+
+ Return nonzero if the CFG was changed (e.g. if the combiner has
+ turned an indirect jump instruction into a direct jump). */
+static int
+combine_instructions (rtx_insn *f, unsigned int nregs)
+{
+ rtx_insn *insn, *next;
+ struct insn_link *links, *nextlinks;
+ rtx_insn *first;
+ basic_block last_bb;
+
+ int new_direct_jump_p = 0;
+
+ for (first = f; first && !NONDEBUG_INSN_P (first); )
+ first = NEXT_INSN (first);
+ if (!first)
+ return 0;
+
+ combine_attempts = 0;
+ combine_merges = 0;
+ combine_extras = 0;
+ combine_successes = 0;
+
+ rtl_hooks = combine_rtl_hooks;
+
+ reg_stat.safe_grow_cleared (nregs, true);
+
+ init_recog_no_volatile ();
+
+ /* Allocate array for insn info. */
+ max_uid_known = get_max_uid ();
+ uid_log_links = XCNEWVEC (struct insn_link *, max_uid_known + 1);
+ uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
+ gcc_obstack_init (&insn_link_obstack);
+
+ nonzero_bits_mode = int_mode_for_size (HOST_BITS_PER_WIDE_INT, 0).require ();
+
+ /* Don't use reg_stat[].nonzero_bits when computing it. This can cause
+ problems when, for example, we have j <<= 1 in a loop. */
+
+ nonzero_sign_valid = 0;
+ label_tick = label_tick_ebb_start = 1;
+
+ /* Scan all SETs and see if we can deduce anything about what
+ bits are known to be zero for some registers and how many copies
+ of the sign bit are known to exist for those registers.
+
+ Also set any known values so that we can use it while searching
+ for what bits are known to be set. */
+
+ setup_incoming_promotions (first);
+ /* Allow the entry block and the first block to fall into the same EBB.
+ Conceptually the incoming promotions are assigned to the entry block. */
+ last_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+
+ create_log_links ();
+ FOR_EACH_BB_FN (this_basic_block, cfun)
+ {
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
+ last_call_luid = 0;
+ mem_last_set = -1;
+
+ label_tick++;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block) != last_bb)
+ label_tick_ebb_start = label_tick;
+ last_bb = this_basic_block;
+
+ FOR_BB_INSNS (this_basic_block, insn)
+ if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
+ {
+ rtx links;
+
+ subst_low_luid = DF_INSN_LUID (insn);
+ subst_insn = insn;
+
+ note_stores (insn, set_nonzero_bits_and_sign_copies, insn);
+ record_dead_and_set_regs (insn);
+
+ if (AUTO_INC_DEC)
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ if (REG_NOTE_KIND (links) == REG_INC)
+ set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
+ insn);
+
+ /* Record the current insn_cost of this instruction. */
+ INSN_COST (insn) = insn_cost (insn, optimize_this_for_speed_p);
+ if (dump_file)
+ {
+ fprintf (dump_file, "insn_cost %d for ", INSN_COST (insn));
+ dump_insn_slim (dump_file, insn);
+ }
+ }
+ }
+
+ nonzero_sign_valid = 1;
+
+ /* Now scan all the insns in forward order. */
+ label_tick = label_tick_ebb_start = 1;
+ init_reg_last ();
+ setup_incoming_promotions (first);
+ last_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ int max_combine = param_max_combine_insns;
+
+ FOR_EACH_BB_FN (this_basic_block, cfun)
+ {
+ rtx_insn *last_combined_insn = NULL;
+
+ /* Ignore instruction combination in basic blocks that are going to
+ be removed as unreachable anyway. See PR82386. */
+ if (EDGE_COUNT (this_basic_block->preds) == 0)
+ continue;
+
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
+ last_call_luid = 0;
+ mem_last_set = -1;
+
+ label_tick++;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block) != last_bb)
+ label_tick_ebb_start = label_tick;
+ last_bb = this_basic_block;
+
+ rtl_profile_for_bb (this_basic_block);
+ for (insn = BB_HEAD (this_basic_block);
+ insn != NEXT_INSN (BB_END (this_basic_block));
+ insn = next ? next : NEXT_INSN (insn))
+ {
+ next = 0;
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ while (last_combined_insn
+ && (!NONDEBUG_INSN_P (last_combined_insn)
+ || last_combined_insn->deleted ()))
+ last_combined_insn = PREV_INSN (last_combined_insn);
+ if (last_combined_insn == NULL_RTX
+ || BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
+ || DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
+ last_combined_insn = insn;
+
+ /* See if we know about function return values before this
+ insn based upon SUBREG flags. */
+ check_promoted_subreg (insn, PATTERN (insn));
+
+ /* See if we can find hardregs and subreg of pseudos in
+ narrower modes. This could help turning TRUNCATEs
+ into SUBREGs. */
+ note_uses (&PATTERN (insn), record_truncated_values, NULL);
+
+ /* Try this insn with each insn it links back to. */
+
+ FOR_EACH_LOG_LINK (links, insn)
+ if ((next = try_combine (insn, links->insn, NULL,
+ NULL, &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "two-insn combine", 1);
+ goto retry;
+ }
+
+ /* Try each sequence of three linked insns ending with this one. */
+
+ if (max_combine >= 3)
+ FOR_EACH_LOG_LINK (links, insn)
+ {
+ rtx_insn *link = links->insn;
+
+ /* If the linked insn has been replaced by a note, then there
+ is no point in pursuing this chain any further. */
+ if (NOTE_P (link))
+ continue;
+
+ FOR_EACH_LOG_LINK (nextlinks, link)
+ if ((next = try_combine (insn, link, nextlinks->insn,
+ NULL, &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "three-insn combine", 1);
+ goto retry;
+ }
+ }
+
+ /* Try combining an insn with two different insns whose results it
+ uses. */
+ if (max_combine >= 3)
+ FOR_EACH_LOG_LINK (links, insn)
+ for (nextlinks = links->next; nextlinks;
+ nextlinks = nextlinks->next)
+ if ((next = try_combine (insn, links->insn,
+ nextlinks->insn, NULL,
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
+
+ {
+ statistics_counter_event (cfun, "three-insn combine", 1);
+ goto retry;
+ }
+
+ /* Try four-instruction combinations. */
+ if (max_combine >= 4)
+ FOR_EACH_LOG_LINK (links, insn)
+ {
+ struct insn_link *next1;
+ rtx_insn *link = links->insn;
+
+ /* If the linked insn has been replaced by a note, then there
+ is no point in pursuing this chain any further. */
+ if (NOTE_P (link))
+ continue;
+
+ FOR_EACH_LOG_LINK (next1, link)
+ {
+ rtx_insn *link1 = next1->insn;
+ if (NOTE_P (link1))
+ continue;
+ /* I0 -> I1 -> I2 -> I3. */
+ FOR_EACH_LOG_LINK (nextlinks, link1)
+ if ((next = try_combine (insn, link, link1,
+ nextlinks->insn,
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "four-insn combine", 1);
+ goto retry;
+ }
+ /* I0, I1 -> I2, I2 -> I3. */
+ for (nextlinks = next1->next; nextlinks;
+ nextlinks = nextlinks->next)
+ if ((next = try_combine (insn, link, link1,
+ nextlinks->insn,
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "four-insn combine", 1);
+ goto retry;
+ }
+ }
+
+ for (next1 = links->next; next1; next1 = next1->next)
+ {
+ rtx_insn *link1 = next1->insn;
+ if (NOTE_P (link1))
+ continue;
+ /* I0 -> I2; I1, I2 -> I3. */
+ FOR_EACH_LOG_LINK (nextlinks, link)
+ if ((next = try_combine (insn, link, link1,
+ nextlinks->insn,
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "four-insn combine", 1);
+ goto retry;
+ }
+ /* I0 -> I1; I1, I2 -> I3. */
+ FOR_EACH_LOG_LINK (nextlinks, link1)
+ if ((next = try_combine (insn, link, link1,
+ nextlinks->insn,
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
+ {
+ statistics_counter_event (cfun, "four-insn combine", 1);
+ goto retry;
+ }
+ }
+ }
+
+ /* Try this insn with each REG_EQUAL note it links back to. */
+ FOR_EACH_LOG_LINK (links, insn)
+ {
+ rtx set, note;
+ rtx_insn *temp = links->insn;
+ if ((set = single_set (temp)) != 0
+ && (note = find_reg_equal_equiv_note (temp)) != 0
+ && (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
+ && ! side_effects_p (SET_SRC (set))
+ /* Avoid using a register that may already been marked
+ dead by an earlier instruction. */
+ && ! unmentioned_reg_p (note, SET_SRC (set))
+ && (GET_MODE (note) == VOIDmode
+ ? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set)))
+ : (GET_MODE (SET_DEST (set)) == GET_MODE (note)
+ && (GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
+ || (GET_MODE (XEXP (SET_DEST (set), 0))
+ == GET_MODE (note))))))
+ {
+ /* Temporarily replace the set's source with the
+ contents of the REG_EQUAL note. The insn will
+ be deleted or recognized by try_combine. */
+ rtx orig_src = SET_SRC (set);
+ rtx orig_dest = SET_DEST (set);
+ if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT)
+ SET_DEST (set) = XEXP (SET_DEST (set), 0);
+ SET_SRC (set) = note;
+ i2mod = temp;
+ i2mod_old_rhs = copy_rtx (orig_src);
+ i2mod_new_rhs = copy_rtx (note);
+ next = try_combine (insn, i2mod, NULL, NULL,
+ &new_direct_jump_p,
+ last_combined_insn);
+ i2mod = NULL;
+ if (next)
+ {
+ statistics_counter_event (cfun, "insn-with-note combine", 1);
+ goto retry;
+ }
+ SET_SRC (set) = orig_src;
+ SET_DEST (set) = orig_dest;
+ }
+ }
+
+ if (!NOTE_P (insn))
+ record_dead_and_set_regs (insn);
+
+retry:
+ ;
+ }
+ }
+
+ default_rtl_profile ();
+ clear_bb_flags ();
+ new_direct_jump_p |= purge_all_dead_edges ();
+ new_direct_jump_p |= delete_noop_moves ();
+
+ /* Clean up. */
+ obstack_free (&insn_link_obstack, NULL);
+ free (uid_log_links);
+ free (uid_insn_cost);
+ reg_stat.release ();
+
+ {
+ struct undo *undo, *next;
+ for (undo = undobuf.frees; undo; undo = next)
+ {
+ next = undo->next;
+ free (undo);
+ }
+ undobuf.frees = 0;
+ }
+
+ total_attempts += combine_attempts;
+ total_merges += combine_merges;
+ total_extras += combine_extras;
+ total_successes += combine_successes;
+
+ nonzero_sign_valid = 0;
+ rtl_hooks = general_rtl_hooks;
+
+ /* Make recognizer allow volatile MEMs again. */
+ init_recog ();
+
+ return new_direct_jump_p;
+}
+
+/* Wipe the last_xxx fields of reg_stat in preparation for another pass. */
+
+static void
+init_reg_last (void)
+{
+ unsigned int i;
+ reg_stat_type *p;
+
+ FOR_EACH_VEC_ELT (reg_stat, i, p)
+ memset (p, 0, offsetof (reg_stat_type, sign_bit_copies));
+}
+
+/* Set up any promoted values for incoming argument registers. */
+
+static void
+setup_incoming_promotions (rtx_insn *first)
+{
+ tree arg;
+ bool strictly_local = false;
+
+ for (arg = DECL_ARGUMENTS (current_function_decl); arg;
+ arg = DECL_CHAIN (arg))
+ {
+ rtx x, reg = DECL_INCOMING_RTL (arg);
+ int uns1, uns3;
+ machine_mode mode1, mode2, mode3, mode4;
+
+ /* Only continue if the incoming argument is in a register. */
+ if (!REG_P (reg))
+ continue;
+
+ /* Determine, if possible, whether all call sites of the current
+ function lie within the current compilation unit. (This does
+ take into account the exporting of a function via taking its
+ address, and so forth.) */
+ strictly_local
+ = cgraph_node::local_info_node (current_function_decl)->local;
+
+ /* The mode and signedness of the argument before any promotions happen
+ (equal to the mode of the pseudo holding it at that stage). */
+ mode1 = TYPE_MODE (TREE_TYPE (arg));
+ uns1 = TYPE_UNSIGNED (TREE_TYPE (arg));
+
+ /* The mode and signedness of the argument after any source language and
+ TARGET_PROMOTE_PROTOTYPES-driven promotions. */
+ mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
+ uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
+
+ /* The mode and signedness of the argument as it is actually passed,
+ see assign_parm_setup_reg in function.c. */
+ mode3 = promote_function_mode (TREE_TYPE (arg), mode1, &uns3,
+ TREE_TYPE (cfun->decl), 0);
+
+ /* The mode of the register in which the argument is being passed. */
+ mode4 = GET_MODE (reg);
+
+ /* Eliminate sign extensions in the callee when:
+ (a) A mode promotion has occurred; */
+ if (mode1 == mode3)
+ continue;
+ /* (b) The mode of the register is the same as the mode of
+ the argument as it is passed; */
+ if (mode3 != mode4)
+ continue;
+ /* (c) There's no language level extension; */
+ if (mode1 == mode2)
+ ;
+ /* (c.1) All callers are from the current compilation unit. If that's
+ the case we don't have to rely on an ABI, we only have to know
+ what we're generating right now, and we know that we will do the
+ mode1 to mode2 promotion with the given sign. */
+ else if (!strictly_local)
+ continue;
+ /* (c.2) The combination of the two promotions is useful. This is
+ true when the signs match, or if the first promotion is unsigned.
+ In the later case, (sign_extend (zero_extend x)) is the same as
+ (zero_extend (zero_extend x)), so make sure to force UNS3 true. */
+ else if (uns1)
+ uns3 = true;
+ else if (uns3)
+ continue;
+
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
+ }
+}
+
+/* If MODE has a precision lower than PREC and SRC is a non-negative constant
+ that would appear negative in MODE, sign-extend SRC for use in nonzero_bits
+ because some machines (maybe most) will actually do the sign-extension and
+ this is the conservative approach.
+
+ ??? For 2.5, try to tighten up the MD files in this regard instead of this
+ kludge. */
+
+static rtx
+sign_extend_short_imm (rtx src, machine_mode mode, unsigned int prec)
+{
+ scalar_int_mode int_mode;
+ if (CONST_INT_P (src)
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) < prec
+ && INTVAL (src) > 0
+ && val_signbit_known_set_p (int_mode, INTVAL (src)))
+ src = GEN_INT (INTVAL (src) | ~GET_MODE_MASK (int_mode));
+
+ return src;
+}
+
+/* Update RSP for pseudo-register X from INSN's REG_EQUAL note (if one exists)
+ and SET. */
+
+static void
+update_rsp_from_reg_equal (reg_stat_type *rsp, rtx_insn *insn, const_rtx set,
+ rtx x)
+{
+ rtx reg_equal_note = insn ? find_reg_equal_equiv_note (insn) : NULL_RTX;
+ unsigned HOST_WIDE_INT bits = 0;
+ rtx reg_equal = NULL, src = SET_SRC (set);
+ unsigned int num = 0;
+
+ if (reg_equal_note)
+ reg_equal = XEXP (reg_equal_note, 0);
+
+ if (SHORT_IMMEDIATES_SIGN_EXTEND)
+ {
+ src = sign_extend_short_imm (src, GET_MODE (x), BITS_PER_WORD);
+ if (reg_equal)
+ reg_equal = sign_extend_short_imm (reg_equal, GET_MODE (x), BITS_PER_WORD);
+ }
+
+ /* Don't call nonzero_bits if it cannot change anything. */
+ if (rsp->nonzero_bits != HOST_WIDE_INT_M1U)
+ {
+ machine_mode mode = GET_MODE (x);
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && HWI_COMPUTABLE_MODE_P (mode))
+ mode = nonzero_bits_mode;
+ bits = nonzero_bits (src, mode);
+ if (reg_equal && bits)
+ bits &= nonzero_bits (reg_equal, mode);
+ rsp->nonzero_bits |= bits;
+ }
+
+ /* Don't call num_sign_bit_copies if it cannot change anything. */
+ if (rsp->sign_bit_copies != 1)
+ {
+ num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
+ if (reg_equal && maybe_ne (num, GET_MODE_PRECISION (GET_MODE (x))))
+ {
+ unsigned int numeq = num_sign_bit_copies (reg_equal, GET_MODE (x));
+ if (num == 0 || numeq > num)
+ num = numeq;
+ }
+ if (rsp->sign_bit_copies == 0 || num < rsp->sign_bit_copies)
+ rsp->sign_bit_copies = num;
+ }
+}
+
+/* Called via note_stores. If X is a pseudo that is narrower than
+ HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
+
+ If we are setting only a portion of X and we can't figure out what
+ portion, assume all bits will be used since we don't know what will
+ be happening.
+
+ Similarly, set how many bits of X are known to be copies of the sign bit
+ at all locations in the function. This is the smallest number implied
+ by any set of X. */
+
+static void
+set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
+{
+ rtx_insn *insn = (rtx_insn *) data;
+ scalar_int_mode mode;
+
+ if (REG_P (x)
+ && REGNO (x) >= FIRST_PSEUDO_REGISTER
+ /* If this register is undefined at the start of the file, we can't
+ say what its contents were. */
+ && ! REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb), REGNO (x))
+ && is_a <scalar_int_mode> (GET_MODE (x), &mode)
+ && HWI_COMPUTABLE_MODE_P (mode))
+ {
+ reg_stat_type *rsp = &reg_stat[REGNO (x)];
+
+ if (set == 0 || GET_CODE (set) == CLOBBER)
+ {
+ rsp->nonzero_bits = GET_MODE_MASK (mode);
+ rsp->sign_bit_copies = 1;
+ return;
+ }
+
+ /* If this register is being initialized using itself, and the
+ register is uninitialized in this basic block, and there are
+ no LOG_LINKS which set the register, then part of the
+ register is uninitialized. In that case we can't assume
+ anything about the number of nonzero bits.
+
+ ??? We could do better if we checked this in
+ reg_{nonzero_bits,num_sign_bit_copies}_for_combine. Then we
+ could avoid making assumptions about the insn which initially
+ sets the register, while still using the information in other
+ insns. We would have to be careful to check every insn
+ involved in the combination. */
+
+ if (insn
+ && reg_referenced_p (x, PATTERN (insn))
+ && !REGNO_REG_SET_P (DF_LR_IN (BLOCK_FOR_INSN (insn)),
+ REGNO (x)))
+ {
+ struct insn_link *link;
+
+ FOR_EACH_LOG_LINK (link, insn)
+ if (dead_or_set_p (link->insn, x))
+ break;
+ if (!link)
+ {
+ rsp->nonzero_bits = GET_MODE_MASK (mode);
+ rsp->sign_bit_copies = 1;
+ return;
+ }
+ }
+
+ /* If this is a complex assignment, see if we can convert it into a
+ simple assignment. */
+ set = expand_field_assignment (set);
+
+ /* If this is a simple assignment, or we have a paradoxical SUBREG,
+ set what we know about X. */
+
+ if (SET_DEST (set) == x
+ || (paradoxical_subreg_p (SET_DEST (set))
+ && SUBREG_REG (SET_DEST (set)) == x))
+ update_rsp_from_reg_equal (rsp, insn, set, x);
+ else
+ {
+ rsp->nonzero_bits = GET_MODE_MASK (mode);
+ rsp->sign_bit_copies = 1;
+ }
+ }
+}
+
+/* See if INSN can be combined into I3. PRED, PRED2, SUCC and SUCC2 are
+ optionally insns that were previously combined into I3 or that will be
+ combined into the merger of INSN and I3. The order is PRED, PRED2,
+ INSN, SUCC, SUCC2, I3.
+
+ Return 0 if the combination is not allowed for any reason.
+
+ If the combination is allowed, *PDEST will be set to the single
+ destination of INSN and *PSRC to the single source, and this function
+ will return 1. */
+
+static int
+can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
+ rtx_insn *pred2 ATTRIBUTE_UNUSED, rtx_insn *succ, rtx_insn *succ2,
+ rtx *pdest, rtx *psrc)
+{
+ int i;
+ const_rtx set = 0;
+ rtx src, dest;
+ rtx_insn *p;
+ rtx link;
+ bool all_adjacent = true;
+ int (*is_volatile_p) (const_rtx);
+
+ if (succ)
+ {
+ if (succ2)
+ {
+ if (next_active_insn (succ2) != i3)
+ all_adjacent = false;
+ if (next_active_insn (succ) != succ2)
+ all_adjacent = false;
+ }
+ else if (next_active_insn (succ) != i3)
+ all_adjacent = false;
+ if (next_active_insn (insn) != succ)
+ all_adjacent = false;
+ }
+ else if (next_active_insn (insn) != i3)
+ all_adjacent = false;
+
+ /* Can combine only if previous insn is a SET of a REG or a SUBREG,
+ or a PARALLEL consisting of such a SET and CLOBBERs.
+
+ If INSN has CLOBBER parallel parts, ignore them for our processing.
+ By definition, these happen during the execution of the insn. When it
+ is merged with another insn, all bets are off. If they are, in fact,
+ needed and aren't also supplied in I3, they may be added by
+ recog_for_combine. Otherwise, it won't match.
+
+ We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED
+ note.
+
+ Get the source and destination of INSN. If more than one, can't
+ combine. */
+
+ if (GET_CODE (PATTERN (insn)) == SET)
+ set = PATTERN (insn);
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL
+ && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
+ {
+ for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+ {
+ rtx elt = XVECEXP (PATTERN (insn), 0, i);
+
+ switch (GET_CODE (elt))
+ {
+ /* This is important to combine floating point insns
+ for the SH4 port. */
+ case USE:
+ /* Combining an isolated USE doesn't make sense.
+ We depend here on combinable_i3pat to reject them. */
+ /* The code below this loop only verifies that the inputs of
+ the SET in INSN do not change. We call reg_set_between_p
+ to verify that the REG in the USE does not change between
+ I3 and INSN.
+ If the USE in INSN was for a pseudo register, the matching
+ insn pattern will likely match any register; combining this
+ with any other USE would only be safe if we knew that the
+ used registers have identical values, or if there was
+ something to tell them apart, e.g. different modes. For
+ now, we forgo such complicated tests and simply disallow
+ combining of USES of pseudo registers with any other USE. */
+ if (REG_P (XEXP (elt, 0))
+ && GET_CODE (PATTERN (i3)) == PARALLEL)
+ {
+ rtx i3pat = PATTERN (i3);
+ int i = XVECLEN (i3pat, 0) - 1;
+ unsigned int regno = REGNO (XEXP (elt, 0));
+
+ do
+ {
+ rtx i3elt = XVECEXP (i3pat, 0, i);
+
+ if (GET_CODE (i3elt) == USE
+ && REG_P (XEXP (i3elt, 0))
+ && (REGNO (XEXP (i3elt, 0)) == regno
+ ? reg_set_between_p (XEXP (elt, 0),
+ PREV_INSN (insn), i3)
+ : regno >= FIRST_PSEUDO_REGISTER))
+ return 0;
+ }
+ while (--i >= 0);
+ }
+ break;
+
+ /* We can ignore CLOBBERs. */
+ case CLOBBER:
+ break;
+
+ case SET:
+ /* Ignore SETs whose result isn't used but not those that
+ have side-effects. */
+ if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
+ && insn_nothrow_p (insn)
+ && !side_effects_p (elt))
+ break;
+
+ /* If we have already found a SET, this is a second one and
+ so we cannot combine with this insn. */
+ if (set)
+ return 0;
+
+ set = elt;
+ break;
+
+ default:
+ /* Anything else means we can't combine. */
+ return 0;
+ }
+ }
+
+ if (set == 0
+ /* If SET_SRC is an ASM_OPERANDS we can't throw away these CLOBBERs,
+ so don't do anything with it. */
+ || GET_CODE (SET_SRC (set)) == ASM_OPERANDS)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (set == 0)
+ return 0;
+
+ /* The simplification in expand_field_assignment may call back to
+ get_last_value, so set safe guard here. */
+ subst_low_luid = DF_INSN_LUID (insn);
+
+ set = expand_field_assignment (set);
+ src = SET_SRC (set), dest = SET_DEST (set);
+
+ /* Do not eliminate user-specified register if it is in an
+ asm input because we may break the register asm usage defined
+ in GCC manual if allow to do so.
+ Be aware that this may cover more cases than we expect but this
+ should be harmless. */
+ if (REG_P (dest) && REG_USERVAR_P (dest) && HARD_REGISTER_P (dest)
+ && extract_asm_operands (PATTERN (i3)))
+ return 0;
+
+ /* Don't eliminate a store in the stack pointer. */
+ if (dest == stack_pointer_rtx
+ /* Don't combine with an insn that sets a register to itself if it has
+ a REG_EQUAL note. This may be part of a LIBCALL sequence. */
+ || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ /* Can't merge an ASM_OPERANDS. */
+ || GET_CODE (src) == ASM_OPERANDS
+ /* Can't merge a function call. */
+ || GET_CODE (src) == CALL
+ /* Don't eliminate a function call argument. */
+ || (CALL_P (i3)
+ && (find_reg_fusage (i3, USE, dest)
+ || (REG_P (dest)
+ && REGNO (dest) < FIRST_PSEUDO_REGISTER
+ && global_regs[REGNO (dest)])))
+ /* Don't substitute into an incremented register. */
+ || FIND_REG_INC_NOTE (i3, dest)
+ || (succ && FIND_REG_INC_NOTE (succ, dest))
+ || (succ2 && FIND_REG_INC_NOTE (succ2, dest))
+ /* Don't substitute into a non-local goto, this confuses CFG. */
+ || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
+ /* Make sure that DEST is not used after INSN but before SUCC, or
+ after SUCC and before SUCC2, or after SUCC2 but before I3. */
+ || (!all_adjacent
+ && ((succ2
+ && (reg_used_between_p (dest, succ2, i3)
+ || reg_used_between_p (dest, succ, succ2)))
+ || (!succ2 && succ && reg_used_between_p (dest, succ, i3))
+ || (!succ2 && !succ && reg_used_between_p (dest, insn, i3))
+ || (succ
+ /* SUCC and SUCC2 can be split halves from a PARALLEL; in
+ that case SUCC is not in the insn stream, so use SUCC2
+ instead for this test. */
+ && reg_used_between_p (dest, insn,
+ succ2
+ && INSN_UID (succ) == INSN_UID (succ2)
+ ? succ2 : succ))))
+ /* Make sure that the value that is to be substituted for the register
+ does not use any registers whose values alter in between. However,
+ If the insns are adjacent, a use can't cross a set even though we
+ think it might (this can happen for a sequence of insns each setting
+ the same destination; last_set of that register might point to
+ a NOTE). If INSN has a REG_EQUIV note, the register is always
+ equivalent to the memory so the substitution is valid even if there
+ are intervening stores. Also, don't move a volatile asm or
+ UNSPEC_VOLATILE across any other insns. */
+ || (! all_adjacent
+ && (((!MEM_P (src)
+ || ! find_reg_note (insn, REG_EQUIV, src))
+ && modified_between_p (src, insn, i3))
+ || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
+ || GET_CODE (src) == UNSPEC_VOLATILE))
+ /* Don't combine across a CALL_INSN, because that would possibly
+ change whether the life span of some REGs crosses calls or not,
+ and it is a pain to update that information.
+ Exception: if source is a constant, moving it later can't hurt.
+ Accept that as a special case. */
+ || (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
+ return 0;
+
+ /* DEST must be a REG. */
+ if (REG_P (dest))
+ {
+ /* If register alignment is being enforced for multi-word items in all
+ cases except for parameters, it is possible to have a register copy
+ insn referencing a hard register that is not allowed to contain the
+ mode being copied and which would not be valid as an operand of most
+ insns. Eliminate this problem by not combining with such an insn.
+
+ Also, on some machines we don't want to extend the life of a hard
+ register. */
+
+ if (REG_P (src)
+ && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
+ && !targetm.hard_regno_mode_ok (REGNO (dest), GET_MODE (dest)))
+ /* Don't extend the life of a hard register unless it is
+ user variable (if we have few registers) or it can't
+ fit into the desired register (meaning something special
+ is going on).
+ Also avoid substituting a return register into I3, because
+ reload can't handle a conflict with constraints of other
+ inputs. */
+ || (REGNO (src) < FIRST_PSEUDO_REGISTER
+ && !targetm.hard_regno_mode_ok (REGNO (src),
+ GET_MODE (src)))))
+ return 0;
+ }
+ else
+ return 0;
+
+
+ if (GET_CODE (PATTERN (i3)) == PARALLEL)
+ for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER)
+ {
+ rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
+
+ /* If the clobber represents an earlyclobber operand, we must not
+ substitute an expression containing the clobbered register.
+ As we do not analyze the constraint strings here, we have to
+ make the conservative assumption. However, if the register is
+ a fixed hard reg, the clobber cannot represent any operand;
+ we leave it up to the machine description to either accept or
+ reject use-and-clobber patterns. */
+ if (!REG_P (reg)
+ || REGNO (reg) >= FIRST_PSEUDO_REGISTER
+ || !fixed_regs[REGNO (reg)])
+ if (reg_overlap_mentioned_p (reg, src))
+ return 0;
+ }
+
+ /* If INSN contains anything volatile, or is an `asm' (whether volatile
+ or not), reject, unless nothing volatile comes between it and I3 */
+
+ if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
+ {
+ /* Make sure neither succ nor succ2 contains a volatile reference. */
+ if (succ2 != 0 && volatile_refs_p (PATTERN (succ2)))
+ return 0;
+ if (succ != 0 && volatile_refs_p (PATTERN (succ)))
+ return 0;
+ /* We'll check insns between INSN and I3 below. */
+ }
+
+ /* If INSN is an asm, and DEST is a hard register, reject, since it has
+ to be an explicit register variable, and was chosen for a reason. */
+
+ if (GET_CODE (src) == ASM_OPERANDS
+ && REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ /* If INSN contains volatile references (specifically volatile MEMs),
+ we cannot combine across any other volatile references.
+ Even if INSN doesn't contain volatile references, any intervening
+ volatile insn might affect machine state. */
+
+ is_volatile_p = volatile_refs_p (PATTERN (insn))
+ ? volatile_refs_p
+ : volatile_insn_p;
+
+ for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
+ if (INSN_P (p) && p != succ && p != succ2 && is_volatile_p (PATTERN (p)))
+ return 0;
+
+ /* If INSN contains an autoincrement or autodecrement, make sure that
+ register is not used between there and I3, and not already used in
+ I3 either. Neither must it be used in PRED or SUCC, if they exist.
+ Also insist that I3 not be a jump if using LRA; if it were one
+ and the incremented register were spilled, we would lose.
+ Reload handles this correctly. */
+
+ if (AUTO_INC_DEC)
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_INC
+ && ((JUMP_P (i3) && targetm.lra_p ())
+ || reg_used_between_p (XEXP (link, 0), insn, i3)
+ || (pred != NULL_RTX
+ && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred)))
+ || (pred2 != NULL_RTX
+ && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred2)))
+ || (succ != NULL_RTX
+ && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ)))
+ || (succ2 != NULL_RTX
+ && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ2)))
+ || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
+ return 0;
+
+ /* If we get here, we have passed all the tests and the combination is
+ to be allowed. */
+
+ *pdest = dest;
+ *psrc = src;
+
+ return 1;
+}
+
+/* LOC is the location within I3 that contains its pattern or the component
+ of a PARALLEL of the pattern. We validate that it is valid for combining.
+
+ One problem is if I3 modifies its output, as opposed to replacing it
+ entirely, we can't allow the output to contain I2DEST, I1DEST or I0DEST as
+ doing so would produce an insn that is not equivalent to the original insns.
+
+ Consider:
+
+ (set (reg:DI 101) (reg:DI 100))
+ (set (subreg:SI (reg:DI 101) 0) <foo>)
+
+ This is NOT equivalent to:
+
+ (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
+ (set (reg:DI 101) (reg:DI 100))])
+
+ Not only does this modify 100 (in which case it might still be valid
+ if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100.
+
+ We can also run into a problem if I2 sets a register that I1
+ uses and I1 gets directly substituted into I3 (not via I2). In that
+ case, we would be getting the wrong value of I2DEST into I3, so we
+ must reject the combination. This case occurs when I2 and I1 both
+ feed into I3, rather than when I1 feeds into I2, which feeds into I3.
+ If I1_NOT_IN_SRC is nonzero, it means that finding I1 in the source
+ of a SET must prevent combination from occurring. The same situation
+ can occur for I0, in which case I0_NOT_IN_SRC is set.
+
+ Before doing the above check, we first try to expand a field assignment
+ into a set of logical operations.
+
+ If PI3_DEST_KILLED is nonzero, it is a pointer to a location in which
+ we place a register that is both set and used within I3. If more than one
+ such register is detected, we fail.
+
+ Return 1 if the combination is valid, zero otherwise. */
+
+static int
+combinable_i3pat (rtx_insn *i3, rtx *loc, rtx i2dest, rtx i1dest, rtx i0dest,
+ int i1_not_in_src, int i0_not_in_src, rtx *pi3dest_killed)
+{
+ rtx x = *loc;
+
+ if (GET_CODE (x) == SET)
+ {
+ rtx set = x ;
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
+ rtx inner_dest = dest;
+ rtx subdest;
+
+ while (GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT)
+ inner_dest = XEXP (inner_dest, 0);
+
+ /* Check for the case where I3 modifies its output, as discussed
+ above. We don't want to prevent pseudos from being combined
+ into the address of a MEM, so only prevent the combination if
+ i1 or i2 set the same MEM. */
+ if ((inner_dest != dest &&
+ (!MEM_P (inner_dest)
+ || rtx_equal_p (i2dest, inner_dest)
+ || (i1dest && rtx_equal_p (i1dest, inner_dest))
+ || (i0dest && rtx_equal_p (i0dest, inner_dest)))
+ && (reg_overlap_mentioned_p (i2dest, inner_dest)
+ || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))
+ || (i0dest && reg_overlap_mentioned_p (i0dest, inner_dest))))
+
+ /* This is the same test done in can_combine_p except we can't test
+ all_adjacent; we don't have to, since this instruction will stay
+ in place, thus we are not considering increasing the lifetime of
+ INNER_DEST.
+
+ Also, if this insn sets a function argument, combining it with
+ something that might need a spill could clobber a previous
+ function argument; the all_adjacent test in can_combine_p also
+ checks this; here, we do a more specific test for this case. */
+
+ || (REG_P (inner_dest)
+ && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+ && !targetm.hard_regno_mode_ok (REGNO (inner_dest),
+ GET_MODE (inner_dest)))
+ || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src))
+ || (i0_not_in_src && reg_overlap_mentioned_p (i0dest, src)))
+ return 0;
+
+ /* If DEST is used in I3, it is being killed in this insn, so
+ record that for later. We have to consider paradoxical
+ subregs here, since they kill the whole register, but we
+ ignore partial subregs, STRICT_LOW_PART, etc.
+ Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
+ STACK_POINTER_REGNUM, since these are always considered to be
+ live. Similarly for ARG_POINTER_REGNUM if it is fixed. */
+ subdest = dest;
+ if (GET_CODE (subdest) == SUBREG && !partial_subreg_p (subdest))
+ subdest = SUBREG_REG (subdest);
+ if (pi3dest_killed
+ && REG_P (subdest)
+ && reg_referenced_p (subdest, PATTERN (i3))
+ && REGNO (subdest) != FRAME_POINTER_REGNUM
+ && (HARD_FRAME_POINTER_IS_FRAME_POINTER
+ || REGNO (subdest) != HARD_FRAME_POINTER_REGNUM)
+ && (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM
+ || (REGNO (subdest) != ARG_POINTER_REGNUM
+ || ! fixed_regs [REGNO (subdest)]))
+ && REGNO (subdest) != STACK_POINTER_REGNUM)
+ {
+ if (*pi3dest_killed)
+ return 0;
+
+ *pi3dest_killed = subdest;
+ }
+ }
+
+ else if (GET_CODE (x) == PARALLEL)
+ {
+ int i;
+
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ if (! combinable_i3pat (i3, &XVECEXP (x, 0, i), i2dest, i1dest, i0dest,
+ i1_not_in_src, i0_not_in_src, pi3dest_killed))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return 1 if X is an arithmetic expression that contains a multiplication
+ and division. We don't count multiplications by powers of two here. */
+
+static int
+contains_muldiv (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case MOD: case DIV: case UMOD: case UDIV:
+ return 1;
+
+ case MULT:
+ return ! (CONST_INT_P (XEXP (x, 1))
+ && pow2p_hwi (UINTVAL (XEXP (x, 1))));
+ default:
+ if (BINARY_P (x))
+ return contains_muldiv (XEXP (x, 0))
+ || contains_muldiv (XEXP (x, 1));
+
+ if (UNARY_P (x))
+ return contains_muldiv (XEXP (x, 0));
+
+ return 0;
+ }
+}
+
+/* Determine whether INSN can be used in a combination. Return nonzero if
+ not. This is used in try_combine to detect early some cases where we
+ can't perform combinations. */
+
+static int
+cant_combine_insn_p (rtx_insn *insn)
+{
+ rtx set;
+ rtx src, dest;
+
+ /* If this isn't really an insn, we can't do anything.
+ This can occur when flow deletes an insn that it has merged into an
+ auto-increment address. */
+ if (!NONDEBUG_INSN_P (insn))
+ return 1;
+
+ /* Never combine loads and stores involving hard regs that are likely
+ to be spilled. The register allocator can usually handle such
+ reg-reg moves by tying. If we allow the combiner to make
+ substitutions of likely-spilled regs, reload might die.
+ As an exception, we allow combinations involving fixed regs; these are
+ not available to the register allocator so there's no risk involved. */
+
+ set = single_set (insn);
+ if (! set)
+ return 0;
+ src = SET_SRC (set);
+ dest = SET_DEST (set);
+ if (GET_CODE (src) == SUBREG)
+ src = SUBREG_REG (src);
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+ if (REG_P (src) && REG_P (dest)
+ && ((HARD_REGISTER_P (src)
+ && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
+#ifdef LEAF_REGISTERS
+ && ! LEAF_REGISTERS [REGNO (src)])
+#else
+ )
+#endif
+ || (HARD_REGISTER_P (dest)
+ && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
+ && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (dest))))))
+ return 1;
+
+ return 0;
+}
+
+struct likely_spilled_retval_info
+{
+ unsigned regno, nregs;
+ unsigned mask;
+};
+
+/* Called via note_stores by likely_spilled_retval_p. Remove from info->mask
+ hard registers that are known to be written to / clobbered in full. */
+static void
+likely_spilled_retval_1 (rtx x, const_rtx set, void *data)
+{
+ struct likely_spilled_retval_info *const info =
+ (struct likely_spilled_retval_info *) data;
+ unsigned regno, nregs;
+ unsigned new_mask;
+
+ if (!REG_P (XEXP (set, 0)))
+ return;
+ regno = REGNO (x);
+ if (regno >= info->regno + info->nregs)
+ return;
+ nregs = REG_NREGS (x);
+ if (regno + nregs <= info->regno)
+ return;
+ new_mask = (2U << (nregs - 1)) - 1;
+ if (regno < info->regno)
+ new_mask >>= info->regno - regno;
+ else
+ new_mask <<= regno - info->regno;
+ info->mask &= ~new_mask;
+}
+
+/* Return nonzero iff part of the return value is live during INSN, and
+ it is likely spilled. This can happen when more than one insn is needed
+ to copy the return value, e.g. when we consider to combine into the
+ second copy insn for a complex value. */
+
+static int
+likely_spilled_retval_p (rtx_insn *insn)
+{
+ rtx_insn *use = BB_END (this_basic_block);
+ rtx reg;
+ rtx_insn *p;
+ unsigned regno, nregs;
+ /* We assume here that no machine mode needs more than
+ 32 hard registers when the value overlaps with a register
+ for which TARGET_FUNCTION_VALUE_REGNO_P is true. */
+ unsigned mask;
+ struct likely_spilled_retval_info info;
+
+ if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
+ return 0;
+ reg = XEXP (PATTERN (use), 0);
+ if (!REG_P (reg) || !targetm.calls.function_value_regno_p (REGNO (reg)))
+ return 0;
+ regno = REGNO (reg);
+ nregs = REG_NREGS (reg);
+ if (nregs == 1)
+ return 0;
+ mask = (2U << (nregs - 1)) - 1;
+
+ /* Disregard parts of the return value that are set later. */
+ info.regno = regno;
+ info.nregs = nregs;
+ info.mask = mask;
+ for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
+ if (INSN_P (p))
+ note_stores (p, likely_spilled_retval_1, &info);
+ mask = info.mask;
+
+ /* Check if any of the (probably) live return value registers is
+ likely spilled. */
+ nregs --;
+ do
+ {
+ if ((mask & 1 << nregs)
+ && targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno + nregs)))
+ return 1;
+ } while (nregs--);
+ return 0;
+}
+
+/* Adjust INSN after we made a change to its destination.
+
+ Changing the destination can invalidate notes that say something about
+ the results of the insn and a LOG_LINK pointing to the insn. */
+
+static void
+adjust_for_new_dest (rtx_insn *insn)
+{
+ /* For notes, be conservative and simply remove them. */
+ remove_reg_equal_equiv_notes (insn, true);
+
+ /* The new insn will have a destination that was previously the destination
+ of an insn just above it. Call distribute_links to make a LOG_LINK from
+ the next use of that destination. */
+
+ rtx set = single_set (insn);
+ gcc_assert (set);
+
+ rtx reg = SET_DEST (set);
+
+ while (GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART
+ || GET_CODE (reg) == SUBREG)
+ reg = XEXP (reg, 0);
+ gcc_assert (REG_P (reg));
+
+ distribute_links (alloc_insn_link (insn, REGNO (reg), NULL));
+
+ df_insn_rescan (insn);
+}
+
+/* Return TRUE if combine can reuse reg X in mode MODE.
+ ADDED_SETS is nonzero if the original set is still required. */
+static bool
+can_change_dest_mode (rtx x, int added_sets, machine_mode mode)
+{
+ unsigned int regno;
+
+ if (!REG_P (x))
+ return false;
+
+ /* Don't change between modes with different underlying register sizes,
+ since this could lead to invalid subregs. */
+ if (maybe_ne (REGMODE_NATURAL_SIZE (mode),
+ REGMODE_NATURAL_SIZE (GET_MODE (x))))
+ return false;
+
+ regno = REGNO (x);
+ /* Allow hard registers if the new mode is legal, and occupies no more
+ registers than the old mode. */
+ if (regno < FIRST_PSEUDO_REGISTER)
+ return (targetm.hard_regno_mode_ok (regno, mode)
+ && REG_NREGS (x) >= hard_regno_nregs (regno, mode));
+
+ /* Or a pseudo that is only used once. */
+ return (regno < reg_n_sets_max
+ && REG_N_SETS (regno) == 1
+ && !added_sets
+ && !REG_USERVAR_P (x));
+}
+
+
+/* Check whether X, the destination of a set, refers to part of
+ the register specified by REG. */
+
+static bool
+reg_subword_p (rtx x, rtx reg)
+{
+ /* Check that reg is an integer mode register. */
+ if (!REG_P (reg) || GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
+ return false;
+
+ if (GET_CODE (x) == STRICT_LOW_PART
+ || GET_CODE (x) == ZERO_EXTRACT)
+ x = XEXP (x, 0);
+
+ return GET_CODE (x) == SUBREG
+ && SUBREG_REG (x) == reg
+ && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
+}
+
+/* Return whether PAT is a PARALLEL of exactly N register SETs followed
+ by an arbitrary number of CLOBBERs. */
+static bool
+is_parallel_of_n_reg_sets (rtx pat, int n)
+{
+ if (GET_CODE (pat) != PARALLEL)
+ return false;
+
+ int len = XVECLEN (pat, 0);
+ if (len < n)
+ return false;
+
+ int i;
+ for (i = 0; i < n; i++)
+ if (GET_CODE (XVECEXP (pat, 0, i)) != SET
+ || !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
+ return false;
+ for ( ; i < len; i++)
+ switch (GET_CODE (XVECEXP (pat, 0, i)))
+ {
+ case CLOBBER:
+ if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/* Return whether INSN, a PARALLEL of N register SETs (and maybe some
+ CLOBBERs), can be split into individual SETs in that order, without
+ changing semantics. */
+static bool
+can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
+{
+ if (!insn_nothrow_p (insn))
+ return false;
+
+ rtx pat = PATTERN (insn);
+
+ int i, j;
+ for (i = 0; i < n; i++)
+ {
+ if (side_effects_p (SET_SRC (XVECEXP (pat, 0, i))))
+ return false;
+
+ rtx reg = SET_DEST (XVECEXP (pat, 0, i));
+
+ for (j = i + 1; j < n; j++)
+ if (reg_referenced_p (reg, XVECEXP (pat, 0, j)))
+ return false;
+ }
+
+ return true;
+}
+
+/* Return whether X is just a single_set, with the source
+ a general_operand. */
+static bool
+is_just_move (rtx_insn *x)
+{
+ rtx set = single_set (x);
+ if (!set)
+ return false;
+
+ return general_operand (SET_SRC (set), VOIDmode);
+}
+
+/* Callback function to count autoincs. */
+
+static int
+count_auto_inc (rtx, rtx, rtx, rtx, rtx, void *arg)
+{
+ (*((int *) arg))++;
+
+ return 0;
+}
+
+/* Try to combine the insns I0, I1 and I2 into I3.
+ Here I0, I1 and I2 appear earlier than I3.
+ I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
+ I3.
+
+ If we are combining more than two insns and the resulting insn is not
+ recognized, try splitting it into two insns. If that happens, I2 and I3
+ are retained and I1/I0 are pseudo-deleted by turning them into a NOTE.
+ Otherwise, I0, I1 and I2 are pseudo-deleted.
+
+ Return 0 if the combination does not work. Then nothing is changed.
+ If we did the combination, return the insn at which combine should
+ resume scanning.
+
+ Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a
+ new direct jump instruction.
+
+ LAST_COMBINED_INSN is either I3, or some insn after I3 that has
+ been I3 passed to an earlier try_combine within the same basic
+ block. */
+
+static rtx_insn *
+try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
+ int *new_direct_jump_p, rtx_insn *last_combined_insn)
+{
+ /* New patterns for I3 and I2, respectively. */
+ rtx newpat, newi2pat = 0;
+ rtvec newpat_vec_with_clobbers = 0;
+ int substed_i2 = 0, substed_i1 = 0, substed_i0 = 0;
+ /* Indicates need to preserve SET in I0, I1 or I2 in I3 if it is not
+ dead. */
+ int added_sets_0, added_sets_1, added_sets_2;
+ /* Total number of SETs to put into I3. */
+ int total_sets;
+ /* Nonzero if I2's or I1's body now appears in I3. */
+ int i2_is_used = 0, i1_is_used = 0;
+ /* INSN_CODEs for new I3, new I2, and user of condition code. */
+ int insn_code_number, i2_code_number = 0, other_code_number = 0;
+ /* Contains I3 if the destination of I3 is used in its source, which means
+ that the old life of I3 is being killed. If that usage is placed into
+ I2 and not in I3, a REG_DEAD note must be made. */
+ rtx i3dest_killed = 0;
+ /* SET_DEST and SET_SRC of I2, I1 and I0. */
+ rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0, i0dest = 0, i0src = 0;
+ /* Copy of SET_SRC of I1 and I0, if needed. */
+ rtx i1src_copy = 0, i0src_copy = 0, i0src_copy2 = 0;
+ /* Set if I2DEST was reused as a scratch register. */
+ bool i2scratch = false;
+ /* The PATTERNs of I0, I1, and I2, or a copy of them in certain cases. */
+ rtx i0pat = 0, i1pat = 0, i2pat = 0;
+ /* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC. */
+ int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0;
+ int i0dest_in_i0src = 0, i1dest_in_i0src = 0, i2dest_in_i0src = 0;
+ int i2dest_killed = 0, i1dest_killed = 0, i0dest_killed = 0;
+ int i1_feeds_i2_n = 0, i0_feeds_i2_n = 0, i0_feeds_i1_n = 0;
+ /* Notes that must be added to REG_NOTES in I3 and I2. */
+ rtx new_i3_notes, new_i2_notes;
+ /* Notes that we substituted I3 into I2 instead of the normal case. */
+ int i3_subst_into_i2 = 0;
+ /* Notes that I1, I2 or I3 is a MULT operation. */
+ int have_mult = 0;
+ int swap_i2i3 = 0;
+ int split_i2i3 = 0;
+ int changed_i3_dest = 0;
+ bool i2_was_move = false, i3_was_move = false;
+ int n_auto_inc = 0;
+
+ int maxreg;
+ rtx_insn *temp_insn;
+ rtx temp_expr;
+ struct insn_link *link;
+ rtx other_pat = 0;
+ rtx new_other_notes;
+ int i;
+ scalar_int_mode dest_mode, temp_mode;
+
+ /* Immediately return if any of I0,I1,I2 are the same insn (I3 can
+ never be). */
+ if (i1 == i2 || i0 == i2 || (i0 && i0 == i1))
+ return 0;
+
+ /* Only try four-insn combinations when there's high likelihood of
+ success. Look for simple insns, such as loads of constants or
+ binary operations involving a constant. */
+ if (i0)
+ {
+ int i;
+ int ngood = 0;
+ int nshift = 0;
+ rtx set0, set3;
+
+ if (!flag_expensive_optimizations)
+ return 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ rtx_insn *insn = i == 0 ? i0 : i == 1 ? i1 : i == 2 ? i2 : i3;
+ rtx set = single_set (insn);
+ rtx src;
+ if (!set)
+ continue;
+ src = SET_SRC (set);
+ if (CONSTANT_P (src))
+ {
+ ngood += 2;
+ break;
+ }
+ else if (BINARY_P (src) && CONSTANT_P (XEXP (src, 1)))
+ ngood++;
+ else if (GET_CODE (src) == ASHIFT || GET_CODE (src) == ASHIFTRT
+ || GET_CODE (src) == LSHIFTRT)
+ nshift++;
+ }
+
+ /* If I0 loads a memory and I3 sets the same memory, then I1 and I2
+ are likely manipulating its value. Ideally we'll be able to combine
+ all four insns into a bitfield insertion of some kind.
+
+ Note the source in I0 might be inside a sign/zero extension and the
+ memory modes in I0 and I3 might be different. So extract the address
+ from the destination of I3 and search for it in the source of I0.
+
+ In the event that there's a match but the source/dest do not actually
+ refer to the same memory, the worst that happens is we try some
+ combinations that we wouldn't have otherwise. */
+ if ((set0 = single_set (i0))
+ /* Ensure the source of SET0 is a MEM, possibly buried inside
+ an extension. */
+ && (GET_CODE (SET_SRC (set0)) == MEM
+ || ((GET_CODE (SET_SRC (set0)) == ZERO_EXTEND
+ || GET_CODE (SET_SRC (set0)) == SIGN_EXTEND)
+ && GET_CODE (XEXP (SET_SRC (set0), 0)) == MEM))
+ && (set3 = single_set (i3))
+ /* Ensure the destination of SET3 is a MEM. */
+ && GET_CODE (SET_DEST (set3)) == MEM
+ /* Would it be better to extract the base address for the MEM
+ in SET3 and look for that? I don't have cases where it matters
+ but I could envision such cases. */
+ && rtx_referenced_p (XEXP (SET_DEST (set3), 0), SET_SRC (set0)))
+ ngood += 2;
+
+ if (ngood < 2 && nshift < 2)
+ return 0;
+ }
+
+ /* Exit early if one of the insns involved can't be used for
+ combinations. */
+ if (CALL_P (i2)
+ || (i1 && CALL_P (i1))
+ || (i0 && CALL_P (i0))
+ || cant_combine_insn_p (i3)
+ || cant_combine_insn_p (i2)
+ || (i1 && cant_combine_insn_p (i1))
+ || (i0 && cant_combine_insn_p (i0))
+ || likely_spilled_retval_p (i3))
+ return 0;
+
+ combine_attempts++;
+ undobuf.other_insn = 0;
+
+ /* Reset the hard register usage information. */
+ CLEAR_HARD_REG_SET (newpat_used_regs);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (i0)
+ fprintf (dump_file, "\nTrying %d, %d, %d -> %d:\n",
+ INSN_UID (i0), INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
+ else if (i1)
+ fprintf (dump_file, "\nTrying %d, %d -> %d:\n",
+ INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
+ else
+ fprintf (dump_file, "\nTrying %d -> %d:\n",
+ INSN_UID (i2), INSN_UID (i3));
+
+ if (i0)
+ dump_insn_slim (dump_file, i0);
+ if (i1)
+ dump_insn_slim (dump_file, i1);
+ dump_insn_slim (dump_file, i2);
+ dump_insn_slim (dump_file, i3);
+ }
+
+ /* If multiple insns feed into one of I2 or I3, they can be in any
+ order. To simplify the code below, reorder them in sequence. */
+ if (i0 && DF_INSN_LUID (i0) > DF_INSN_LUID (i2))
+ std::swap (i0, i2);
+ if (i0 && DF_INSN_LUID (i0) > DF_INSN_LUID (i1))
+ std::swap (i0, i1);
+ if (i1 && DF_INSN_LUID (i1) > DF_INSN_LUID (i2))
+ std::swap (i1, i2);
+
+ added_links_insn = 0;
+ added_notes_insn = 0;
+
+ /* First check for one important special case that the code below will
+ not handle. Namely, the case where I1 is zero, I2 is a PARALLEL
+ and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case,
+ we may be able to replace that destination with the destination of I3.
+ This occurs in the common code where we compute both a quotient and
+ remainder into a structure, in which case we want to do the computation
+ directly into the structure to avoid register-register copies.
+
+ Note that this case handles both multiple sets in I2 and also cases
+ where I2 has a number of CLOBBERs inside the PARALLEL.
+
+ We make very conservative checks below and only try to handle the
+ most common cases of this. For example, we only handle the case
+ where I2 and I3 are adjacent to avoid making difficult register
+ usage tests. */
+
+ if (i1 == 0 && NONJUMP_INSN_P (i3) && GET_CODE (PATTERN (i3)) == SET
+ && REG_P (SET_SRC (PATTERN (i3)))
+ && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
+ && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
+ && GET_CODE (PATTERN (i2)) == PARALLEL
+ && ! side_effects_p (SET_DEST (PATTERN (i3)))
+ /* If the dest of I3 is a ZERO_EXTRACT or STRICT_LOW_PART, the code
+ below would need to check what is inside (and reg_overlap_mentioned_p
+ doesn't support those codes anyway). Don't allow those destinations;
+ the resulting insn isn't likely to be recognized anyway. */
+ && GET_CODE (SET_DEST (PATTERN (i3))) != ZERO_EXTRACT
+ && GET_CODE (SET_DEST (PATTERN (i3))) != STRICT_LOW_PART
+ && ! reg_overlap_mentioned_p (SET_SRC (PATTERN (i3)),
+ SET_DEST (PATTERN (i3)))
+ && next_active_insn (i2) == i3)
+ {
+ rtx p2 = PATTERN (i2);
+
+ /* Make sure that the destination of I3,
+ which we are going to substitute into one output of I2,
+ is not used within another output of I2. We must avoid making this:
+ (parallel [(set (mem (reg 69)) ...)
+ (set (reg 69) ...)])
+ which is not well-defined as to order of actions.
+ (Besides, reload can't handle output reloads for this.)
+
+ The problem can also happen if the dest of I3 is a memory ref,
+ if another dest in I2 is an indirect memory ref.
+
+ Neither can this PARALLEL be an asm. We do not allow combining
+ that usually (see can_combine_p), so do not here either. */
+ bool ok = true;
+ for (i = 0; ok && i < XVECLEN (p2, 0); i++)
+ {
+ if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
+ || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
+ && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
+ SET_DEST (XVECEXP (p2, 0, i))))
+ ok = false;
+ else if (GET_CODE (XVECEXP (p2, 0, i)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (p2, 0, i))) == ASM_OPERANDS)
+ ok = false;
+ }
+
+ if (ok)
+ for (i = 0; i < XVECLEN (p2, 0); i++)
+ if (GET_CODE (XVECEXP (p2, 0, i)) == SET
+ && SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3)))
+ {
+ combine_merges++;
+
+ subst_insn = i3;
+ subst_low_luid = DF_INSN_LUID (i2);
+
+ added_sets_2 = added_sets_1 = added_sets_0 = 0;
+ i2src = SET_SRC (XVECEXP (p2, 0, i));
+ i2dest = SET_DEST (XVECEXP (p2, 0, i));
+ i2dest_killed = dead_or_set_p (i2, i2dest);
+
+ /* Replace the dest in I2 with our dest and make the resulting
+ insn the new pattern for I3. Then skip to where we validate
+ the pattern. Everything was set up above. */
+ SUBST (SET_DEST (XVECEXP (p2, 0, i)), SET_DEST (PATTERN (i3)));
+ newpat = p2;
+ i3_subst_into_i2 = 1;
+ goto validate_replacement;
+ }
+ }
+
+ /* If I2 is setting a pseudo to a constant and I3 is setting some
+ sub-part of it to another constant, merge them by making a new
+ constant. */
+ if (i1 == 0
+ && (temp_expr = single_set (i2)) != 0
+ && is_a <scalar_int_mode> (GET_MODE (SET_DEST (temp_expr)), &temp_mode)
+ && CONST_SCALAR_INT_P (SET_SRC (temp_expr))
+ && GET_CODE (PATTERN (i3)) == SET
+ && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
+ && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp_expr)))
+ {
+ rtx dest = SET_DEST (PATTERN (i3));
+ rtx temp_dest = SET_DEST (temp_expr);
+ int offset = -1;
+ int width = 0;
+
+ if (GET_CODE (dest) == ZERO_EXTRACT)
+ {
+ if (CONST_INT_P (XEXP (dest, 1))
+ && CONST_INT_P (XEXP (dest, 2))
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (dest, 0)),
+ &dest_mode))
+ {
+ width = INTVAL (XEXP (dest, 1));
+ offset = INTVAL (XEXP (dest, 2));
+ dest = XEXP (dest, 0);
+ if (BITS_BIG_ENDIAN)
+ offset = GET_MODE_PRECISION (dest_mode) - width - offset;
+ }
+ }
+ else
+ {
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+ if (is_a <scalar_int_mode> (GET_MODE (dest), &dest_mode))
+ {
+ width = GET_MODE_PRECISION (dest_mode);
+ offset = 0;
+ }
+ }
+
+ if (offset >= 0)
+ {
+ /* If this is the low part, we're done. */
+ if (subreg_lowpart_p (dest))
+ ;
+ /* Handle the case where inner is twice the size of outer. */
+ else if (GET_MODE_PRECISION (temp_mode)
+ == 2 * GET_MODE_PRECISION (dest_mode))
+ offset += GET_MODE_PRECISION (dest_mode);
+ /* Otherwise give up for now. */
+ else
+ offset = -1;
+ }
+
+ if (offset >= 0)
+ {
+ rtx inner = SET_SRC (PATTERN (i3));
+ rtx outer = SET_SRC (temp_expr);
+
+ wide_int o = wi::insert (rtx_mode_t (outer, temp_mode),
+ rtx_mode_t (inner, dest_mode),
+ offset, width);
+
+ combine_merges++;
+ subst_insn = i3;
+ subst_low_luid = DF_INSN_LUID (i2);
+ added_sets_2 = added_sets_1 = added_sets_0 = 0;
+ i2dest = temp_dest;
+ i2dest_killed = dead_or_set_p (i2, i2dest);
+
+ /* Replace the source in I2 with the new constant and make the
+ resulting insn the new pattern for I3. Then skip to where we
+ validate the pattern. Everything was set up above. */
+ SUBST (SET_SRC (temp_expr),
+ immed_wide_int_const (o, temp_mode));
+
+ newpat = PATTERN (i2);
+
+ /* The dest of I3 has been replaced with the dest of I2. */
+ changed_i3_dest = 1;
+ goto validate_replacement;
+ }
+ }
+
+ /* If we have no I1 and I2 looks like:
+ (parallel [(set (reg:CC X) (compare:CC OP (const_int 0)))
+ (set Y OP)])
+ make up a dummy I1 that is
+ (set Y OP)
+ and change I2 to be
+ (set (reg:CC X) (compare:CC Y (const_int 0)))
+
+ (We can ignore any trailing CLOBBERs.)
+
+ This undoes a previous combination and allows us to match a branch-and-
+ decrement insn. */
+
+ if (i1 == 0
+ && is_parallel_of_n_reg_sets (PATTERN (i2), 2)
+ && (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0))))
+ == MODE_CC)
+ && GET_CODE (SET_SRC (XVECEXP (PATTERN (i2), 0, 0))) == COMPARE
+ && XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 1) == const0_rtx
+ && rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0),
+ SET_SRC (XVECEXP (PATTERN (i2), 0, 1)))
+ && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
+ && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3))
+ {
+ /* We make I1 with the same INSN_UID as I2. This gives it
+ the same DF_INSN_LUID for value tracking. Our fake I1 will
+ never appear in the insn stream so giving it the same INSN_UID
+ as I2 will not cause a problem. */
+
+ i1 = gen_rtx_INSN (VOIDmode, NULL, i2, BLOCK_FOR_INSN (i2),
+ XVECEXP (PATTERN (i2), 0, 1), INSN_LOCATION (i2),
+ -1, NULL_RTX);
+ INSN_UID (i1) = INSN_UID (i2);
+
+ SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
+ SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
+ SET_DEST (PATTERN (i1)));
+ unsigned int regno = REGNO (SET_DEST (PATTERN (i1)));
+ SUBST_LINK (LOG_LINKS (i2),
+ alloc_insn_link (i1, regno, LOG_LINKS (i2)));
+ }
+
+ /* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs),
+ make those two SETs separate I1 and I2 insns, and make an I0 that is
+ the original I1. */
+ if (i0 == 0
+ && is_parallel_of_n_reg_sets (PATTERN (i2), 2)
+ && can_split_parallel_of_n_reg_sets (i2, 2)
+ && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
+ && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3)
+ && !reg_set_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
+ && !reg_set_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3))
+ {
+ /* If there is no I1, there is no I0 either. */
+ i0 = i1;
+
+ /* We make I1 with the same INSN_UID as I2. This gives it
+ the same DF_INSN_LUID for value tracking. Our fake I1 will
+ never appear in the insn stream so giving it the same INSN_UID
+ as I2 will not cause a problem. */
+
+ i1 = gen_rtx_INSN (VOIDmode, NULL, i2, BLOCK_FOR_INSN (i2),
+ XVECEXP (PATTERN (i2), 0, 0), INSN_LOCATION (i2),
+ -1, NULL_RTX);
+ INSN_UID (i1) = INSN_UID (i2);
+
+ SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 1));
+ }
+
+ /* Verify that I2 and maybe I1 and I0 can be combined into I3. */
+ if (!can_combine_p (i2, i3, i0, i1, NULL, NULL, &i2dest, &i2src))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Can't combine i2 into i3\n");
+ undo_all ();
+ return 0;
+ }
+ if (i1 && !can_combine_p (i1, i3, i0, NULL, i2, NULL, &i1dest, &i1src))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Can't combine i1 into i3\n");
+ undo_all ();
+ return 0;
+ }
+ if (i0 && !can_combine_p (i0, i3, NULL, NULL, i1, i2, &i0dest, &i0src))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Can't combine i0 into i3\n");
+ undo_all ();
+ return 0;
+ }
+
+ /* Record whether i2 and i3 are trivial moves. */
+ i2_was_move = is_just_move (i2);
+ i3_was_move = is_just_move (i3);
+
+ /* Record whether I2DEST is used in I2SRC and similarly for the other
+ cases. Knowing this will help in register status updating below. */
+ i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
+ i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src);
+ i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src);
+ i0dest_in_i0src = i0 && reg_overlap_mentioned_p (i0dest, i0src);
+ i1dest_in_i0src = i0 && reg_overlap_mentioned_p (i1dest, i0src);
+ i2dest_in_i0src = i0 && reg_overlap_mentioned_p (i2dest, i0src);
+ i2dest_killed = dead_or_set_p (i2, i2dest);
+ i1dest_killed = i1 && dead_or_set_p (i1, i1dest);
+ i0dest_killed = i0 && dead_or_set_p (i0, i0dest);
+
+ /* For the earlier insns, determine which of the subsequent ones they
+ feed. */
+ i1_feeds_i2_n = i1 && insn_a_feeds_b (i1, i2);
+ i0_feeds_i1_n = i0 && insn_a_feeds_b (i0, i1);
+ i0_feeds_i2_n = (i0 && (!i0_feeds_i1_n ? insn_a_feeds_b (i0, i2)
+ : (!reg_overlap_mentioned_p (i1dest, i0dest)
+ && reg_overlap_mentioned_p (i0dest, i2src))));
+
+ /* Ensure that I3's pattern can be the destination of combines. */
+ if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest, i0dest,
+ i1 && i2dest_in_i1src && !i1_feeds_i2_n,
+ i0 && ((i2dest_in_i0src && !i0_feeds_i2_n)
+ || (i1dest_in_i0src && !i0_feeds_i1_n)),
+ &i3dest_killed))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* See if any of the insns is a MULT operation. Unless one is, we will
+ reject a combination that is, since it must be slower. Be conservative
+ here. */
+ if (GET_CODE (i2src) == MULT
+ || (i1 != 0 && GET_CODE (i1src) == MULT)
+ || (i0 != 0 && GET_CODE (i0src) == MULT)
+ || (GET_CODE (PATTERN (i3)) == SET
+ && GET_CODE (SET_SRC (PATTERN (i3))) == MULT))
+ have_mult = 1;
+
+ /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd.
+ We used to do this EXCEPT in one case: I3 has a post-inc in an
+ output operand. However, that exception can give rise to insns like
+ mov r3,(r3)+
+ which is a famous insn on the PDP-11 where the value of r3 used as the
+ source was model-dependent. Avoid this sort of thing. */
+
+#if 0
+ if (!(GET_CODE (PATTERN (i3)) == SET
+ && REG_P (SET_SRC (PATTERN (i3)))
+ && MEM_P (SET_DEST (PATTERN (i3)))
+ && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC
+ || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC)))
+ /* It's not the exception. */
+#endif
+ if (AUTO_INC_DEC)
+ {
+ rtx link;
+ for (link = REG_NOTES (i3); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_INC
+ && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2))
+ || (i1 != 0
+ && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1)))))
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+
+ /* See if the SETs in I1 or I2 need to be kept around in the merged
+ instruction: whenever the value set there is still needed past I3.
+ For the SET in I2, this is easy: we see if I2DEST dies or is set in I3.
+
+ For the SET in I1, we have two cases: if I1 and I2 independently feed
+ into I3, the set in I1 needs to be kept around unless I1DEST dies
+ or is set in I3. Otherwise (if I1 feeds I2 which feeds I3), the set
+ in I1 needs to be kept around unless I1DEST dies or is set in either
+ I2 or I3. The same considerations apply to I0. */
+
+ added_sets_2 = !dead_or_set_p (i3, i2dest);
+
+ if (i1)
+ added_sets_1 = !(dead_or_set_p (i3, i1dest)
+ || (i1_feeds_i2_n && dead_or_set_p (i2, i1dest)));
+ else
+ added_sets_1 = 0;
+
+ if (i0)
+ added_sets_0 = !(dead_or_set_p (i3, i0dest)
+ || (i0_feeds_i1_n && dead_or_set_p (i1, i0dest))
+ || ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
+ && dead_or_set_p (i2, i0dest)));
+ else
+ added_sets_0 = 0;
+
+ /* We are about to copy insns for the case where they need to be kept
+ around. Check that they can be copied in the merged instruction. */
+
+ if (targetm.cannot_copy_insn_p
+ && ((added_sets_2 && targetm.cannot_copy_insn_p (i2))
+ || (i1 && added_sets_1 && targetm.cannot_copy_insn_p (i1))
+ || (i0 && added_sets_0 && targetm.cannot_copy_insn_p (i0))))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* We cannot safely duplicate volatile references in any case. */
+
+ if ((added_sets_2 && volatile_refs_p (PATTERN (i2)))
+ || (added_sets_1 && volatile_refs_p (PATTERN (i1)))
+ || (added_sets_0 && volatile_refs_p (PATTERN (i0))))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* Count how many auto_inc expressions there were in the original insns;
+ we need to have the same number in the resulting patterns. */
+
+ if (i0)
+ for_each_inc_dec (PATTERN (i0), count_auto_inc, &n_auto_inc);
+ if (i1)
+ for_each_inc_dec (PATTERN (i1), count_auto_inc, &n_auto_inc);
+ for_each_inc_dec (PATTERN (i2), count_auto_inc, &n_auto_inc);
+ for_each_inc_dec (PATTERN (i3), count_auto_inc, &n_auto_inc);
+
+ /* If the set in I2 needs to be kept around, we must make a copy of
+ PATTERN (I2), so that when we substitute I1SRC for I1DEST in
+ PATTERN (I2), we are only substituting for the original I1DEST, not into
+ an already-substituted copy. This also prevents making self-referential
+ rtx. If I2 is a PARALLEL, we just need the piece that assigns I2SRC to
+ I2DEST. */
+
+ if (added_sets_2)
+ {
+ if (GET_CODE (PATTERN (i2)) == PARALLEL)
+ i2pat = gen_rtx_SET (i2dest, copy_rtx (i2src));
+ else
+ i2pat = copy_rtx (PATTERN (i2));
+ }
+
+ if (added_sets_1)
+ {
+ if (GET_CODE (PATTERN (i1)) == PARALLEL)
+ i1pat = gen_rtx_SET (i1dest, copy_rtx (i1src));
+ else
+ i1pat = copy_rtx (PATTERN (i1));
+ }
+
+ if (added_sets_0)
+ {
+ if (GET_CODE (PATTERN (i0)) == PARALLEL)
+ i0pat = gen_rtx_SET (i0dest, copy_rtx (i0src));
+ else
+ i0pat = copy_rtx (PATTERN (i0));
+ }
+
+ combine_merges++;
+
+ /* Substitute in the latest insn for the regs set by the earlier ones. */
+
+ maxreg = max_reg_num ();
+
+ subst_insn = i3;
+
+ /* Many machines have insns that can both perform an
+ arithmetic operation and set the condition code. These operations will
+ be represented as a PARALLEL with the first element of the vector
+ being a COMPARE of an arithmetic operation with the constant zero.
+ The second element of the vector will set some pseudo to the result
+ of the same arithmetic operation. If we simplify the COMPARE, we won't
+ match such a pattern and so will generate an extra insn. Here we test
+ for this case, where both the comparison and the operation result are
+ needed, and make the PARALLEL by just replacing I2DEST in I3SRC with
+ I2SRC. Later we will make the PARALLEL that contains I2. */
+
+ if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET
+ && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE
+ && CONST_INT_P (XEXP (SET_SRC (PATTERN (i3)), 1))
+ && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
+ {
+ rtx newpat_dest;
+ rtx *cc_use_loc = NULL;
+ rtx_insn *cc_use_insn = NULL;
+ rtx op0 = i2src, op1 = XEXP (SET_SRC (PATTERN (i3)), 1);
+ machine_mode compare_mode, orig_compare_mode;
+ enum rtx_code compare_code = UNKNOWN, orig_compare_code = UNKNOWN;
+ scalar_int_mode mode;
+
+ newpat = PATTERN (i3);
+ newpat_dest = SET_DEST (newpat);
+ compare_mode = orig_compare_mode = GET_MODE (newpat_dest);
+
+ if (undobuf.other_insn == 0
+ && (cc_use_loc = find_single_use (SET_DEST (newpat), i3,
+ &cc_use_insn)))
+ {
+ compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
+ if (is_a <scalar_int_mode> (GET_MODE (i2dest), &mode))
+ compare_code = simplify_compare_const (compare_code, mode,
+ op0, &op1);
+ target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
+ }
+
+ /* Do the rest only if op1 is const0_rtx, which may be the
+ result of simplification. */
+ if (op1 == const0_rtx)
+ {
+ /* If a single use of the CC is found, prepare to modify it
+ when SELECT_CC_MODE returns a new CC-class mode, or when
+ the above simplify_compare_const() returned a new comparison
+ operator. undobuf.other_insn is assigned the CC use insn
+ when modifying it. */
+ if (cc_use_loc)
+ {
+#ifdef SELECT_CC_MODE
+ machine_mode new_mode
+ = SELECT_CC_MODE (compare_code, op0, op1);
+ if (new_mode != orig_compare_mode
+ && can_change_dest_mode (SET_DEST (newpat),
+ added_sets_2, new_mode))
+ {
+ unsigned int regno = REGNO (newpat_dest);
+ compare_mode = new_mode;
+ if (regno < FIRST_PSEUDO_REGISTER)
+ newpat_dest = gen_rtx_REG (compare_mode, regno);
+ else
+ {
+ SUBST_MODE (regno_reg_rtx[regno], compare_mode);
+ newpat_dest = regno_reg_rtx[regno];
+ }
+ }
+#endif
+ /* Cases for modifying the CC-using comparison. */
+ if (compare_code != orig_compare_code
+ /* ??? Do we need to verify the zero rtx? */
+ && XEXP (*cc_use_loc, 1) == const0_rtx)
+ {
+ /* Replace cc_use_loc with entire new RTX. */
+ SUBST (*cc_use_loc,
+ gen_rtx_fmt_ee (compare_code, GET_MODE (*cc_use_loc),
+ newpat_dest, const0_rtx));
+ undobuf.other_insn = cc_use_insn;
+ }
+ else if (compare_mode != orig_compare_mode)
+ {
+ /* Just replace the CC reg with a new mode. */
+ SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
+ undobuf.other_insn = cc_use_insn;
+ }
+ }
+
+ /* Now we modify the current newpat:
+ First, SET_DEST(newpat) is updated if the CC mode has been
+ altered. For targets without SELECT_CC_MODE, this should be
+ optimized away. */
+ if (compare_mode != orig_compare_mode)
+ SUBST (SET_DEST (newpat), newpat_dest);
+ /* This is always done to propagate i2src into newpat. */
+ SUBST (SET_SRC (newpat),
+ gen_rtx_COMPARE (compare_mode, op0, op1));
+ /* Create new version of i2pat if needed; the below PARALLEL
+ creation needs this to work correctly. */
+ if (! rtx_equal_p (i2src, op0))
+ i2pat = gen_rtx_SET (i2dest, op0);
+ i2_is_used = 1;
+ }
+ }
+
+ if (i2_is_used == 0)
+ {
+ /* It is possible that the source of I2 or I1 may be performing
+ an unneeded operation, such as a ZERO_EXTEND of something
+ that is known to have the high part zero. Handle that case
+ by letting subst look at the inner insns.
+
+ Another way to do this would be to have a function that tries
+ to simplify a single insn instead of merging two or more
+ insns. We don't do this because of the potential of infinite
+ loops and because of the potential extra memory required.
+ However, doing it the way we are is a bit of a kludge and
+ doesn't catch all cases.
+
+ But only do this if -fexpensive-optimizations since it slows
+ things down and doesn't usually win.
+
+ This is not done in the COMPARE case above because the
+ unmodified I2PAT is used in the PARALLEL and so a pattern
+ with a modified I2SRC would not match. */
+
+ if (flag_expensive_optimizations)
+ {
+ /* Pass pc_rtx so no substitutions are done, just
+ simplifications. */
+ if (i1)
+ {
+ subst_low_luid = DF_INSN_LUID (i1);
+ i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
+ }
+
+ subst_low_luid = DF_INSN_LUID (i2);
+ i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
+ }
+
+ n_occurrences = 0; /* `subst' counts here */
+ subst_low_luid = DF_INSN_LUID (i2);
+
+ /* If I1 feeds into I2 and I1DEST is in I1SRC, we need to make a unique
+ copy of I2SRC each time we substitute it, in order to avoid creating
+ self-referential RTL when we will be substituting I1SRC for I1DEST
+ later. Likewise if I0 feeds into I2, either directly or indirectly
+ through I1, and I0DEST is in I0SRC. */
+ newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0,
+ (i1_feeds_i2_n && i1dest_in_i1src)
+ || ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
+ && i0dest_in_i0src));
+ substed_i2 = 1;
+
+ /* Record whether I2's body now appears within I3's body. */
+ i2_is_used = n_occurrences;
+ }
+
+ /* If we already got a failure, don't try to do more. Otherwise, try to
+ substitute I1 if we have it. */
+
+ if (i1 && GET_CODE (newpat) != CLOBBER)
+ {
+ /* Before we can do this substitution, we must redo the test done
+ above (see detailed comments there) that ensures I1DEST isn't
+ mentioned in any SETs in NEWPAT that are field assignments. */
+ if (!combinable_i3pat (NULL, &newpat, i1dest, NULL_RTX, NULL_RTX,
+ 0, 0, 0))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ n_occurrences = 0;
+ subst_low_luid = DF_INSN_LUID (i1);
+
+ /* If the following substitution will modify I1SRC, make a copy of it
+ for the case where it is substituted for I1DEST in I2PAT later. */
+ if (added_sets_2 && i1_feeds_i2_n)
+ i1src_copy = copy_rtx (i1src);
+
+ /* If I0 feeds into I1 and I0DEST is in I0SRC, we need to make a unique
+ copy of I1SRC each time we substitute it, in order to avoid creating
+ self-referential RTL when we will be substituting I0SRC for I0DEST
+ later. */
+ newpat = subst (newpat, i1dest, i1src, 0, 0,
+ i0_feeds_i1_n && i0dest_in_i0src);
+ substed_i1 = 1;
+
+ /* Record whether I1's body now appears within I3's body. */
+ i1_is_used = n_occurrences;
+ }
+
+ /* Likewise for I0 if we have it. */
+
+ if (i0 && GET_CODE (newpat) != CLOBBER)
+ {
+ if (!combinable_i3pat (NULL, &newpat, i0dest, NULL_RTX, NULL_RTX,
+ 0, 0, 0))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* If the following substitution will modify I0SRC, make a copy of it
+ for the case where it is substituted for I0DEST in I1PAT later. */
+ if (added_sets_1 && i0_feeds_i1_n)
+ i0src_copy = copy_rtx (i0src);
+ /* And a copy for I0DEST in I2PAT substitution. */
+ if (added_sets_2 && ((i0_feeds_i1_n && i1_feeds_i2_n)
+ || (i0_feeds_i2_n)))
+ i0src_copy2 = copy_rtx (i0src);
+
+ n_occurrences = 0;
+ subst_low_luid = DF_INSN_LUID (i0);
+ newpat = subst (newpat, i0dest, i0src, 0, 0, 0);
+ substed_i0 = 1;
+ }
+
+ if (n_auto_inc)
+ {
+ int new_n_auto_inc = 0;
+ for_each_inc_dec (newpat, count_auto_inc, &new_n_auto_inc);
+
+ if (n_auto_inc != new_n_auto_inc)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Number of auto_inc expressions changed\n");
+ undo_all ();
+ return 0;
+ }
+ }
+
+ /* Fail if an autoincrement side-effect has been duplicated. Be careful
+ to count all the ways that I2SRC and I1SRC can be used. */
+ if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0
+ && i2_is_used + added_sets_2 > 1)
+ || (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
+ && (i1_is_used + added_sets_1 + (added_sets_2 && i1_feeds_i2_n)
+ > 1))
+ || (i0 != 0 && FIND_REG_INC_NOTE (i0, NULL_RTX) != 0
+ && (n_occurrences + added_sets_0
+ + (added_sets_1 && i0_feeds_i1_n)
+ + (added_sets_2 && i0_feeds_i2_n)
+ > 1))
+ /* Fail if we tried to make a new register. */
+ || max_reg_num () != maxreg
+ /* Fail if we couldn't do something and have a CLOBBER. */
+ || GET_CODE (newpat) == CLOBBER
+ /* Fail if this new pattern is a MULT and we didn't have one before
+ at the outer level. */
+ || (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT
+ && ! have_mult))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* If the actions of the earlier insns must be kept
+ in addition to substituting them into the latest one,
+ we must make a new PARALLEL for the latest insn
+ to hold additional the SETs. */
+
+ if (added_sets_0 || added_sets_1 || added_sets_2)
+ {
+ int extra_sets = added_sets_0 + added_sets_1 + added_sets_2;
+ combine_extras++;
+
+ if (GET_CODE (newpat) == PARALLEL)
+ {
+ rtvec old = XVEC (newpat, 0);
+ total_sets = XVECLEN (newpat, 0) + extra_sets;
+ newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
+ memcpy (XVEC (newpat, 0)->elem, &old->elem[0],
+ sizeof (old->elem[0]) * old->num_elem);
+ }
+ else
+ {
+ rtx old = newpat;
+ total_sets = 1 + extra_sets;
+ newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
+ XVECEXP (newpat, 0, 0) = old;
+ }
+
+ if (added_sets_0)
+ XVECEXP (newpat, 0, --total_sets) = i0pat;
+
+ if (added_sets_1)
+ {
+ rtx t = i1pat;
+ if (i0_feeds_i1_n)
+ t = subst (t, i0dest, i0src_copy ? i0src_copy : i0src, 0, 0, 0);
+
+ XVECEXP (newpat, 0, --total_sets) = t;
+ }
+ if (added_sets_2)
+ {
+ rtx t = i2pat;
+ if (i1_feeds_i2_n)
+ t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0, 0,
+ i0_feeds_i1_n && i0dest_in_i0src);
+ if ((i0_feeds_i1_n && i1_feeds_i2_n) || i0_feeds_i2_n)
+ t = subst (t, i0dest, i0src_copy2 ? i0src_copy2 : i0src, 0, 0, 0);
+
+ XVECEXP (newpat, 0, --total_sets) = t;
+ }
+ }
+
+ validate_replacement:
+
+ /* Note which hard regs this insn has as inputs. */
+ mark_used_regs_combine (newpat);
+
+ /* If recog_for_combine fails, it strips existing clobbers. If we'll
+ consider splitting this pattern, we might need these clobbers. */
+ if (i1 && GET_CODE (newpat) == PARALLEL
+ && GET_CODE (XVECEXP (newpat, 0, XVECLEN (newpat, 0) - 1)) == CLOBBER)
+ {
+ int len = XVECLEN (newpat, 0);
+
+ newpat_vec_with_clobbers = rtvec_alloc (len);
+ for (i = 0; i < len; i++)
+ RTVEC_ELT (newpat_vec_with_clobbers, i) = XVECEXP (newpat, 0, i);
+ }
+
+ /* We have recognized nothing yet. */
+ insn_code_number = -1;
+
+ /* See if this is a PARALLEL of two SETs where one SET's destination is
+ a register that is unused and this isn't marked as an instruction that
+ might trap in an EH region. In that case, we just need the other SET.
+ We prefer this over the PARALLEL.
+
+ This can occur when simplifying a divmod insn. We *must* test for this
+ case here because the code below that splits two independent SETs doesn't
+ handle this case correctly when it updates the register status.
+
+ It's pointless doing this if we originally had two sets, one from
+ i3, and one from i2. Combining then splitting the parallel results
+ in the original i2 again plus an invalid insn (which we delete).
+ The net effect is only to move instructions around, which makes
+ debug info less accurate.
+
+ If the remaining SET came from I2 its destination should not be used
+ between I2 and I3. See PR82024. */
+
+ if (!(added_sets_2 && i1 == 0)
+ && is_parallel_of_n_reg_sets (newpat, 2)
+ && asm_noperands (newpat) < 0)
+ {
+ rtx set0 = XVECEXP (newpat, 0, 0);
+ rtx set1 = XVECEXP (newpat, 0, 1);
+ rtx oldpat = newpat;
+
+ if (((REG_P (SET_DEST (set1))
+ && find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
+ || (GET_CODE (SET_DEST (set1)) == SUBREG
+ && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
+ && insn_nothrow_p (i3)
+ && !side_effects_p (SET_SRC (set1)))
+ {
+ newpat = set0;
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ }
+
+ else if (((REG_P (SET_DEST (set0))
+ && find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
+ || (GET_CODE (SET_DEST (set0)) == SUBREG
+ && find_reg_note (i3, REG_UNUSED,
+ SUBREG_REG (SET_DEST (set0)))))
+ && insn_nothrow_p (i3)
+ && !side_effects_p (SET_SRC (set0)))
+ {
+ rtx dest = SET_DEST (set1);
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+ if (!reg_used_between_p (dest, i2, i3))
+ {
+ newpat = set1;
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+ if (insn_code_number >= 0)
+ changed_i3_dest = 1;
+ }
+ }
+
+ if (insn_code_number < 0)
+ newpat = oldpat;
+ }
+
+ /* Is the result of combination a valid instruction? */
+ if (insn_code_number < 0)
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+ /* If we were combining three insns and the result is a simple SET
+ with no ASM_OPERANDS that wasn't recognized, try to split it into two
+ insns. There are two ways to do this. It can be split using a
+ machine-specific method (like when you have an addition of a large
+ constant) or by combine in the function find_split_point. */
+
+ if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
+ && asm_noperands (newpat) < 0)
+ {
+ rtx parallel, *split;
+ rtx_insn *m_split_insn;
+
+ /* See if the MD file can split NEWPAT. If it can't, see if letting it
+ use I2DEST as a scratch register will help. In the latter case,
+ convert I2DEST to the mode of the source of NEWPAT if we can. */
+
+ m_split_insn = combine_split_insns (newpat, i3);
+
+ /* We can only use I2DEST as a scratch reg if it doesn't overlap any
+ inputs of NEWPAT. */
+
+ /* ??? If I2DEST is not safe, and I1DEST exists, then it would be
+ possible to try that as a scratch reg. This would require adding
+ more code to make it work though. */
+
+ if (m_split_insn == 0 && ! reg_overlap_mentioned_p (i2dest, newpat))
+ {
+ machine_mode new_mode = GET_MODE (SET_DEST (newpat));
+
+ /* ??? Reusing i2dest without resetting the reg_stat entry for it
+ (temporarily, until we are committed to this instruction
+ combination) does not work: for example, any call to nonzero_bits
+ on the register (from a splitter in the MD file, for example)
+ will get the old information, which is invalid.
+
+ Since nowadays we can create registers during combine just fine,
+ we should just create a new one here, not reuse i2dest. */
+
+ /* First try to split using the original register as a
+ scratch register. */
+ parallel = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, newpat,
+ gen_rtx_CLOBBER (VOIDmode,
+ i2dest)));
+ m_split_insn = combine_split_insns (parallel, i3);
+
+ /* If that didn't work, try changing the mode of I2DEST if
+ we can. */
+ if (m_split_insn == 0
+ && new_mode != GET_MODE (i2dest)
+ && new_mode != VOIDmode
+ && can_change_dest_mode (i2dest, added_sets_2, new_mode))
+ {
+ machine_mode old_mode = GET_MODE (i2dest);
+ rtx ni2dest;
+
+ if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
+ ni2dest = gen_rtx_REG (new_mode, REGNO (i2dest));
+ else
+ {
+ SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], new_mode);
+ ni2dest = regno_reg_rtx[REGNO (i2dest)];
+ }
+
+ parallel = (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, newpat,
+ gen_rtx_CLOBBER (VOIDmode,
+ ni2dest))));
+ m_split_insn = combine_split_insns (parallel, i3);
+
+ if (m_split_insn == 0
+ && REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
+ {
+ struct undo *buf;
+
+ adjust_reg_mode (regno_reg_rtx[REGNO (i2dest)], old_mode);
+ buf = undobuf.undos;
+ undobuf.undos = buf->next;
+ buf->next = undobuf.frees;
+ undobuf.frees = buf;
+ }
+ }
+
+ i2scratch = m_split_insn != 0;
+ }
+
+ /* If recog_for_combine has discarded clobbers, try to use them
+ again for the split. */
+ if (m_split_insn == 0 && newpat_vec_with_clobbers)
+ {
+ parallel = gen_rtx_PARALLEL (VOIDmode, newpat_vec_with_clobbers);
+ m_split_insn = combine_split_insns (parallel, i3);
+ }
+
+ if (m_split_insn && NEXT_INSN (m_split_insn) == NULL_RTX)
+ {
+ rtx m_split_pat = PATTERN (m_split_insn);
+ insn_code_number = recog_for_combine (&m_split_pat, i3, &new_i3_notes);
+ if (insn_code_number >= 0)
+ newpat = m_split_pat;
+ }
+ else if (m_split_insn && NEXT_INSN (NEXT_INSN (m_split_insn)) == NULL_RTX
+ && (next_nonnote_nondebug_insn (i2) == i3
+ || !modified_between_p (PATTERN (m_split_insn), i2, i3)))
+ {
+ rtx i2set, i3set;
+ rtx newi3pat = PATTERN (NEXT_INSN (m_split_insn));
+ newi2pat = PATTERN (m_split_insn);
+
+ i3set = single_set (NEXT_INSN (m_split_insn));
+ i2set = single_set (m_split_insn);
+
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+
+ /* If I2 or I3 has multiple SETs, we won't know how to track
+ register status, so don't use these insns. If I2's destination
+ is used between I2 and I3, we also can't use these insns. */
+
+ if (i2_code_number >= 0 && i2set && i3set
+ && (next_nonnote_nondebug_insn (i2) == i3
+ || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
+ insn_code_number = recog_for_combine (&newi3pat, i3,
+ &new_i3_notes);
+ if (insn_code_number >= 0)
+ newpat = newi3pat;
+
+ /* It is possible that both insns now set the destination of I3.
+ If so, we must show an extra use of it. */
+
+ if (insn_code_number >= 0)
+ {
+ rtx new_i3_dest = SET_DEST (i3set);
+ rtx new_i2_dest = SET_DEST (i2set);
+
+ while (GET_CODE (new_i3_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i3_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i3_dest) == SUBREG)
+ new_i3_dest = XEXP (new_i3_dest, 0);
+
+ while (GET_CODE (new_i2_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i2_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i2_dest) == SUBREG)
+ new_i2_dest = XEXP (new_i2_dest, 0);
+
+ if (REG_P (new_i3_dest)
+ && REG_P (new_i2_dest)
+ && REGNO (new_i3_dest) == REGNO (new_i2_dest)
+ && REGNO (new_i2_dest) < reg_n_sets_max)
+ INC_REG_N_SETS (REGNO (new_i2_dest), 1);
+ }
+ }
+
+ /* If we can split it and use I2DEST, go ahead and see if that
+ helps things be recognized. Verify that none of the registers
+ are set between I2 and I3. */
+ if (insn_code_number < 0
+ && (split = find_split_point (&newpat, i3, false)) != 0
+ /* We need I2DEST in the proper mode. If it is a hard register
+ or the only use of a pseudo, we can change its mode.
+ Make sure we don't change a hard register to have a mode that
+ isn't valid for it, or change the number of registers. */
+ && (GET_MODE (*split) == GET_MODE (i2dest)
+ || GET_MODE (*split) == VOIDmode
+ || can_change_dest_mode (i2dest, added_sets_2,
+ GET_MODE (*split)))
+ && (next_nonnote_nondebug_insn (i2) == i3
+ || !modified_between_p (*split, i2, i3))
+ /* We can't overwrite I2DEST if its value is still used by
+ NEWPAT. */
+ && ! reg_referenced_p (i2dest, newpat))
+ {
+ rtx newdest = i2dest;
+ enum rtx_code split_code = GET_CODE (*split);
+ machine_mode split_mode = GET_MODE (*split);
+ bool subst_done = false;
+ newi2pat = NULL_RTX;
+
+ i2scratch = true;
+
+ /* *SPLIT may be part of I2SRC, so make sure we have the
+ original expression around for later debug processing.
+ We should not need I2SRC any more in other cases. */
+ if (MAY_HAVE_DEBUG_BIND_INSNS)
+ i2src = copy_rtx (i2src);
+ else
+ i2src = NULL;
+
+ /* Get NEWDEST as a register in the proper mode. We have already
+ validated that we can do this. */
+ if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
+ {
+ if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
+ newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
+ else
+ {
+ SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], split_mode);
+ newdest = regno_reg_rtx[REGNO (i2dest)];
+ }
+ }
+
+ /* If *SPLIT is a (mult FOO (const_int pow2)), convert it to
+ an ASHIFT. This can occur if it was inside a PLUS and hence
+ appeared to be a memory address. This is a kludge. */
+ if (split_code == MULT
+ && CONST_INT_P (XEXP (*split, 1))
+ && INTVAL (XEXP (*split, 1)) > 0
+ && (i = exact_log2 (UINTVAL (XEXP (*split, 1)))) >= 0)
+ {
+ rtx i_rtx = gen_int_shift_amount (split_mode, i);
+ SUBST (*split, gen_rtx_ASHIFT (split_mode,
+ XEXP (*split, 0), i_rtx));
+ /* Update split_code because we may not have a multiply
+ anymore. */
+ split_code = GET_CODE (*split);
+ }
+
+ /* Similarly for (plus (mult FOO (const_int pow2))). */
+ if (split_code == PLUS
+ && GET_CODE (XEXP (*split, 0)) == MULT
+ && CONST_INT_P (XEXP (XEXP (*split, 0), 1))
+ && INTVAL (XEXP (XEXP (*split, 0), 1)) > 0
+ && (i = exact_log2 (UINTVAL (XEXP (XEXP (*split, 0), 1)))) >= 0)
+ {
+ rtx nsplit = XEXP (*split, 0);
+ rtx i_rtx = gen_int_shift_amount (GET_MODE (nsplit), i);
+ SUBST (XEXP (*split, 0), gen_rtx_ASHIFT (GET_MODE (nsplit),
+ XEXP (nsplit, 0),
+ i_rtx));
+ /* Update split_code because we may not have a multiply
+ anymore. */
+ split_code = GET_CODE (*split);
+ }
+
+#ifdef INSN_SCHEDULING
+ /* If *SPLIT is a paradoxical SUBREG, when we split it, it should
+ be written as a ZERO_EXTEND. */
+ if (split_code == SUBREG && MEM_P (SUBREG_REG (*split)))
+ {
+ /* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's
+ what it really is. */
+ if (load_extend_op (GET_MODE (SUBREG_REG (*split)))
+ == SIGN_EXTEND)
+ SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode,
+ SUBREG_REG (*split)));
+ else
+ SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
+ SUBREG_REG (*split)));
+ }
+#endif
+
+ /* Attempt to split binary operators using arithmetic identities. */
+ if (BINARY_P (SET_SRC (newpat))
+ && split_mode == GET_MODE (SET_SRC (newpat))
+ && ! side_effects_p (SET_SRC (newpat)))
+ {
+ rtx setsrc = SET_SRC (newpat);
+ machine_mode mode = GET_MODE (setsrc);
+ enum rtx_code code = GET_CODE (setsrc);
+ rtx src_op0 = XEXP (setsrc, 0);
+ rtx src_op1 = XEXP (setsrc, 1);
+
+ /* Split "X = Y op Y" as "Z = Y; X = Z op Z". */
+ if (rtx_equal_p (src_op0, src_op1))
+ {
+ newi2pat = gen_rtx_SET (newdest, src_op0);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((P op Q) op R) op S" where op is PLUS or MULT. */
+ else if ((code == PLUS || code == MULT)
+ && GET_CODE (src_op0) == code
+ && GET_CODE (XEXP (src_op0, 0)) == code
+ && (INTEGRAL_MODE_P (mode)
+ || (FLOAT_MODE_P (mode)
+ && flag_unsafe_math_optimizations)))
+ {
+ rtx p = XEXP (XEXP (src_op0, 0), 0);
+ rtx q = XEXP (XEXP (src_op0, 0), 1);
+ rtx r = XEXP (src_op0, 1);
+ rtx s = src_op1;
+
+ /* Split both "((X op Y) op X) op Y" and
+ "((X op Y) op Y) op X" as "T op T" where T is
+ "X op Y". */
+ if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+ || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+ {
+ newi2pat = gen_rtx_SET (newdest, XEXP (src_op0, 0));
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((X op X) op Y) op Y)" as "T op T" where
+ T is "X op Y". */
+ else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+ {
+ rtx tmp = simplify_gen_binary (code, mode, p, r);
+ newi2pat = gen_rtx_SET (newdest, tmp);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ }
+ }
+
+ if (!subst_done)
+ {
+ newi2pat = gen_rtx_SET (newdest, *split);
+ SUBST (*split, newdest);
+ }
+
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+
+ /* recog_for_combine might have added CLOBBERs to newi2pat.
+ Make sure NEWPAT does not depend on the clobbered regs. */
+ if (GET_CODE (newi2pat) == PARALLEL)
+ for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+ {
+ rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+ if (reg_overlap_mentioned_p (reg, newpat))
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+
+ /* If the split point was a MULT and we didn't have one before,
+ don't use one now. */
+ if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ }
+ }
+
+ /* Check for a case where we loaded from memory in a narrow mode and
+ then sign extended it, but we need both registers. In that case,
+ we have a PARALLEL with both loads from the same memory location.
+ We can split this into a load from memory followed by a register-register
+ copy. This saves at least one insn, more if register allocation can
+ eliminate the copy.
+
+ We cannot do this if the destination of the first assignment is a
+ condition code register. We eliminate this case by making sure
+ the SET_DEST and SET_SRC have the same mode.
+
+ We cannot do this if the destination of the second assignment is
+ a register that we have already assumed is zero-extended. Similarly
+ for a SUBREG of such a register. */
+
+ else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0
+ && GET_CODE (newpat) == PARALLEL
+ && XVECLEN (newpat, 0) == 2
+ && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (newpat, 0, 0))) == SIGN_EXTEND
+ && (GET_MODE (SET_DEST (XVECEXP (newpat, 0, 0)))
+ == GET_MODE (SET_SRC (XVECEXP (newpat, 0, 0))))
+ && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
+ && rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
+ XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
+ && !modified_between_p (SET_SRC (XVECEXP (newpat, 0, 1)), i2, i3)
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
+ && ! (temp_expr = SET_DEST (XVECEXP (newpat, 0, 1)),
+ (REG_P (temp_expr)
+ && reg_stat[REGNO (temp_expr)].nonzero_bits != 0
+ && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+ BITS_PER_WORD)
+ && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+ HOST_BITS_PER_INT)
+ && (reg_stat[REGNO (temp_expr)].nonzero_bits
+ != GET_MODE_MASK (word_mode))))
+ && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
+ && (temp_expr = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
+ (REG_P (temp_expr)
+ && reg_stat[REGNO (temp_expr)].nonzero_bits != 0
+ && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+ BITS_PER_WORD)
+ && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+ HOST_BITS_PER_INT)
+ && (reg_stat[REGNO (temp_expr)].nonzero_bits
+ != GET_MODE_MASK (word_mode)))))
+ && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
+ SET_SRC (XVECEXP (newpat, 0, 1)))
+ && ! find_reg_note (i3, REG_UNUSED,
+ SET_DEST (XVECEXP (newpat, 0, 0))))
+ {
+ rtx ni2dest;
+
+ newi2pat = XVECEXP (newpat, 0, 0);
+ ni2dest = SET_DEST (XVECEXP (newpat, 0, 0));
+ newpat = XVECEXP (newpat, 0, 1);
+ SUBST (SET_SRC (newpat),
+ gen_lowpart (GET_MODE (SET_SRC (newpat)), ni2dest));
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+
+ if (i2_code_number >= 0)
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+ if (insn_code_number >= 0)
+ swap_i2i3 = 1;
+ }
+
+ /* Similarly, check for a case where we have a PARALLEL of two independent
+ SETs but we started with three insns. In this case, we can do the sets
+ as two separate insns. This case occurs when some SET allows two
+ other insns to combine, but the destination of that SET is still live.
+
+ Also do this if we started with two insns and (at least) one of the
+ resulting sets is a noop; this noop will be deleted later.
+
+ Also do this if we started with two insns neither of which was a simple
+ move. */
+
+ else if (insn_code_number < 0 && asm_noperands (newpat) < 0
+ && GET_CODE (newpat) == PARALLEL
+ && XVECLEN (newpat, 0) == 2
+ && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
+ && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
+ && (i1
+ || set_noop_p (XVECEXP (newpat, 0, 0))
+ || set_noop_p (XVECEXP (newpat, 0, 1))
+ || (!i2_was_move && !i3_was_move))
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
+ && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
+ && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
+ XVECEXP (newpat, 0, 0))
+ && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
+ XVECEXP (newpat, 0, 1))
+ && ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0)))
+ && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1)))))
+ {
+ rtx set0 = XVECEXP (newpat, 0, 0);
+ rtx set1 = XVECEXP (newpat, 0, 1);
+
+ /* Normally, it doesn't matter which of the two is done first, but
+ one which uses any regs/memory set in between i2 and i3 can't
+ be first. The PARALLEL might also have been pre-existing in i3,
+ so we need to make sure that we won't wrongly hoist a SET to i2
+ that would conflict with a death note present in there, or would
+ have its dest modified between i2 and i3. */
+ if (!modified_between_p (SET_SRC (set1), i2, i3)
+ && !(REG_P (SET_DEST (set1))
+ && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
+ && !(GET_CODE (SET_DEST (set1)) == SUBREG
+ && find_reg_note (i2, REG_DEAD,
+ SUBREG_REG (SET_DEST (set1))))
+ && !modified_between_p (SET_DEST (set1), i2, i3)
+ /* If I3 is a jump, ensure that set0 is a jump so that
+ we do not create invalid RTL. */
+ && (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx)
+ )
+ {
+ newi2pat = set1;
+ newpat = set0;
+ }
+ else if (!modified_between_p (SET_SRC (set0), i2, i3)
+ && !(REG_P (SET_DEST (set0))
+ && find_reg_note (i2, REG_DEAD, SET_DEST (set0)))
+ && !(GET_CODE (SET_DEST (set0)) == SUBREG
+ && find_reg_note (i2, REG_DEAD,
+ SUBREG_REG (SET_DEST (set0))))
+ && !modified_between_p (SET_DEST (set0), i2, i3)
+ /* If I3 is a jump, ensure that set1 is a jump so that
+ we do not create invalid RTL. */
+ && (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx)
+ )
+ {
+ newi2pat = set0;
+ newpat = set1;
+ }
+ else
+ {
+ undo_all ();
+ return 0;
+ }
+
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+
+ if (i2_code_number >= 0)
+ {
+ /* recog_for_combine might have added CLOBBERs to newi2pat.
+ Make sure NEWPAT does not depend on the clobbered regs. */
+ if (GET_CODE (newi2pat) == PARALLEL)
+ {
+ for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+ {
+ rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+ if (reg_overlap_mentioned_p (reg, newpat))
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+ }
+
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+ if (insn_code_number >= 0)
+ split_i2i3 = 1;
+ }
+ }
+
+ /* If it still isn't recognized, fail and change things back the way they
+ were. */
+ if ((insn_code_number < 0
+ /* Is the result a reasonable ASM_OPERANDS? */
+ && (! check_asm_operands (newpat) || added_sets_1 || added_sets_2)))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ /* If we had to change another insn, make sure it is valid also. */
+ if (undobuf.other_insn)
+ {
+ CLEAR_HARD_REG_SET (newpat_used_regs);
+
+ other_pat = PATTERN (undobuf.other_insn);
+ other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
+ &new_other_notes);
+
+ if (other_code_number < 0 && ! check_asm_operands (other_pat))
+ {
+ undo_all ();
+ return 0;
+ }
+ }
+
+ /* Only allow this combination if insn_cost reports that the
+ replacement instructions are cheaper than the originals. */
+ if (!combine_validate_cost (i0, i1, i2, i3, newpat, newi2pat, other_pat))
+ {
+ undo_all ();
+ return 0;
+ }
+
+ if (MAY_HAVE_DEBUG_BIND_INSNS)
+ {
+ struct undo *undo;
+
+ for (undo = undobuf.undos; undo; undo = undo->next)
+ if (undo->kind == UNDO_MODE)
+ {
+ rtx reg = *undo->where.r;
+ machine_mode new_mode = GET_MODE (reg);
+ machine_mode old_mode = undo->old_contents.m;
+
+ /* Temporarily revert mode back. */
+ adjust_reg_mode (reg, old_mode);
+
+ if (reg == i2dest && i2scratch)
+ {
+ /* If we used i2dest as a scratch register with a
+ different mode, substitute it for the original
+ i2src while its original mode is temporarily
+ restored, and then clear i2scratch so that we don't
+ do it again later. */
+ propagate_for_debug (i2, last_combined_insn, reg, i2src,
+ this_basic_block);
+ i2scratch = false;
+ /* Put back the new mode. */
+ adjust_reg_mode (reg, new_mode);
+ }
+ else
+ {
+ rtx tempreg = gen_raw_REG (old_mode, REGNO (reg));
+ rtx_insn *first, *last;
+
+ if (reg == i2dest)
+ {
+ first = i2;
+ last = last_combined_insn;
+ }
+ else
+ {
+ first = i3;
+ last = undobuf.other_insn;
+ gcc_assert (last);
+ if (DF_INSN_LUID (last)
+ < DF_INSN_LUID (last_combined_insn))
+ last = last_combined_insn;
+ }
+
+ /* We're dealing with a reg that changed mode but not
+ meaning, so we want to turn it into a subreg for
+ the new mode. However, because of REG sharing and
+ because its mode had already changed, we have to do
+ it in two steps. First, replace any debug uses of
+ reg, with its original mode temporarily restored,
+ with this copy we have created; then, replace the
+ copy with the SUBREG of the original shared reg,
+ once again changed to the new mode. */
+ propagate_for_debug (first, last, reg, tempreg,
+ this_basic_block);
+ adjust_reg_mode (reg, new_mode);
+ propagate_for_debug (first, last, tempreg,
+ lowpart_subreg (old_mode, reg, new_mode),
+ this_basic_block);
+ }
+ }
+ }
+
+ /* If we will be able to accept this, we have made a
+ change to the destination of I3. This requires us to
+ do a few adjustments. */
+
+ if (changed_i3_dest)
+ {
+ PATTERN (i3) = newpat;
+ adjust_for_new_dest (i3);
+ }
+
+ /* We now know that we can do this combination. Merge the insns and
+ update the status of registers and LOG_LINKS. */
+
+ if (undobuf.other_insn)
+ {
+ rtx note, next;
+
+ PATTERN (undobuf.other_insn) = other_pat;
+
+ /* If any of the notes in OTHER_INSN were REG_DEAD or REG_UNUSED,
+ ensure that they are still valid. Then add any non-duplicate
+ notes added by recog_for_combine. */
+ for (note = REG_NOTES (undobuf.other_insn); note; note = next)
+ {
+ next = XEXP (note, 1);
+
+ if ((REG_NOTE_KIND (note) == REG_DEAD
+ && !reg_referenced_p (XEXP (note, 0),
+ PATTERN (undobuf.other_insn)))
+ ||(REG_NOTE_KIND (note) == REG_UNUSED
+ && !reg_set_p (XEXP (note, 0),
+ PATTERN (undobuf.other_insn)))
+ /* Simply drop equal note since it may be no longer valid
+ for other_insn. It may be possible to record that CC
+ register is changed and only discard those notes, but
+ in practice it's unnecessary complication and doesn't
+ give any meaningful improvement.
+
+ See PR78559. */
+ || REG_NOTE_KIND (note) == REG_EQUAL
+ || REG_NOTE_KIND (note) == REG_EQUIV)
+ remove_note (undobuf.other_insn, note);
+ }
+
+ distribute_notes (new_other_notes, undobuf.other_insn,
+ undobuf.other_insn, NULL, NULL_RTX, NULL_RTX,
+ NULL_RTX);
+ }
+
+ if (swap_i2i3)
+ {
+ /* I3 now uses what used to be its destination and which is now
+ I2's destination. This requires us to do a few adjustments. */
+ PATTERN (i3) = newpat;
+ adjust_for_new_dest (i3);
+ }
+
+ if (swap_i2i3 || split_i2i3)
+ {
+ /* We might need a LOG_LINK from I3 to I2. But then we used to
+ have one, so we still will.
+
+ However, some later insn might be using I2's dest and have
+ a LOG_LINK pointing at I3. We should change it to point at
+ I2 instead. */
+
+ /* newi2pat is usually a SET here; however, recog_for_combine might
+ have added some clobbers. */
+ rtx x = newi2pat;
+ if (GET_CODE (x) == PARALLEL)
+ x = XVECEXP (newi2pat, 0, 0);
+
+ if (REG_P (SET_DEST (x))
+ || (GET_CODE (SET_DEST (x)) == SUBREG
+ && REG_P (SUBREG_REG (SET_DEST (x)))))
+ {
+ unsigned int regno = reg_or_subregno (SET_DEST (x));
+
+ bool done = false;
+ for (rtx_insn *insn = NEXT_INSN (i3);
+ !done
+ && insn
+ && NONDEBUG_INSN_P (insn)
+ && BLOCK_FOR_INSN (insn) == this_basic_block;
+ insn = NEXT_INSN (insn))
+ {
+ struct insn_link *link;
+ FOR_EACH_LOG_LINK (link, insn)
+ if (link->insn == i3 && link->regno == regno)
+ {
+ link->insn = i2;
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ {
+ rtx i3notes, i2notes, i1notes = 0, i0notes = 0;
+ struct insn_link *i3links, *i2links, *i1links = 0, *i0links = 0;
+ rtx midnotes = 0;
+ int from_luid;
+ /* Compute which registers we expect to eliminate. newi2pat may be setting
+ either i3dest or i2dest, so we must check it. */
+ rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
+ || i2dest_in_i2src || i2dest_in_i1src || i2dest_in_i0src
+ || !i2dest_killed
+ ? 0 : i2dest);
+ /* For i1, we need to compute both local elimination and global
+ elimination information with respect to newi2pat because i1dest
+ may be the same as i3dest, in which case newi2pat may be setting
+ i1dest. Global information is used when distributing REG_DEAD
+ note for i2 and i3, in which case it does matter if newi2pat sets
+ i1dest or not.
+
+ Local information is used when distributing REG_DEAD note for i1,
+ in which case it doesn't matter if newi2pat sets i1dest or not.
+ See PR62151, if we have four insns combination:
+ i0: r0 <- i0src
+ i1: r1 <- i1src (using r0)
+ REG_DEAD (r0)
+ i2: r0 <- i2src (using r1)
+ i3: r3 <- i3src (using r0)
+ ix: using r0
+ From i1's point of view, r0 is eliminated, no matter if it is set
+ by newi2pat or not. In other words, REG_DEAD info for r0 in i1
+ should be discarded.
+
+ Note local information only affects cases in forms like "I1->I2->I3",
+ "I0->I1->I2->I3" or "I0&I1->I2, I2->I3". For other cases like
+ "I0->I1, I1&I2->I3" or "I1&I2->I3", newi2pat won't set i1dest or
+ i0dest anyway. */
+ rtx local_elim_i1 = (i1 == 0 || i1dest_in_i1src || i1dest_in_i0src
+ || !i1dest_killed
+ ? 0 : i1dest);
+ rtx elim_i1 = (local_elim_i1 == 0
+ || (newi2pat && reg_set_p (i1dest, newi2pat))
+ ? 0 : i1dest);
+ /* Same case as i1. */
+ rtx local_elim_i0 = (i0 == 0 || i0dest_in_i0src || !i0dest_killed
+ ? 0 : i0dest);
+ rtx elim_i0 = (local_elim_i0 == 0
+ || (newi2pat && reg_set_p (i0dest, newi2pat))
+ ? 0 : i0dest);
+
+ /* Get the old REG_NOTES and LOG_LINKS from all our insns and
+ clear them. */
+ i3notes = REG_NOTES (i3), i3links = LOG_LINKS (i3);
+ i2notes = REG_NOTES (i2), i2links = LOG_LINKS (i2);
+ if (i1)
+ i1notes = REG_NOTES (i1), i1links = LOG_LINKS (i1);
+ if (i0)
+ i0notes = REG_NOTES (i0), i0links = LOG_LINKS (i0);
+
+ /* Ensure that we do not have something that should not be shared but
+ occurs multiple times in the new insns. Check this by first
+ resetting all the `used' flags and then copying anything is shared. */
+
+ reset_used_flags (i3notes);
+ reset_used_flags (i2notes);
+ reset_used_flags (i1notes);
+ reset_used_flags (i0notes);
+ reset_used_flags (newpat);
+ reset_used_flags (newi2pat);
+ if (undobuf.other_insn)
+ reset_used_flags (PATTERN (undobuf.other_insn));
+
+ i3notes = copy_rtx_if_shared (i3notes);
+ i2notes = copy_rtx_if_shared (i2notes);
+ i1notes = copy_rtx_if_shared (i1notes);
+ i0notes = copy_rtx_if_shared (i0notes);
+ newpat = copy_rtx_if_shared (newpat);
+ newi2pat = copy_rtx_if_shared (newi2pat);
+ if (undobuf.other_insn)
+ reset_used_flags (PATTERN (undobuf.other_insn));
+
+ INSN_CODE (i3) = insn_code_number;
+ PATTERN (i3) = newpat;
+
+ if (CALL_P (i3) && CALL_INSN_FUNCTION_USAGE (i3))
+ {
+ for (rtx link = CALL_INSN_FUNCTION_USAGE (i3); link;
+ link = XEXP (link, 1))
+ {
+ if (substed_i2)
+ {
+ /* I2SRC must still be meaningful at this point. Some
+ splitting operations can invalidate I2SRC, but those
+ operations do not apply to calls. */
+ gcc_assert (i2src);
+ XEXP (link, 0) = simplify_replace_rtx (XEXP (link, 0),
+ i2dest, i2src);
+ }
+ if (substed_i1)
+ XEXP (link, 0) = simplify_replace_rtx (XEXP (link, 0),
+ i1dest, i1src);
+ if (substed_i0)
+ XEXP (link, 0) = simplify_replace_rtx (XEXP (link, 0),
+ i0dest, i0src);
+ }
+ }
+
+ if (undobuf.other_insn)
+ INSN_CODE (undobuf.other_insn) = other_code_number;
+
+ /* We had one special case above where I2 had more than one set and
+ we replaced a destination of one of those sets with the destination
+ of I3. In that case, we have to update LOG_LINKS of insns later
+ in this basic block. Note that this (expensive) case is rare.
+
+ Also, in this case, we must pretend that all REG_NOTEs for I2
+ actually came from I3, so that REG_UNUSED notes from I2 will be
+ properly handled. */
+
+ if (i3_subst_into_i2)
+ {
+ for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
+ if ((GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == SET
+ || GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == CLOBBER)
+ && REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i)))
+ && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
+ && ! find_reg_note (i2, REG_UNUSED,
+ SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
+ for (temp_insn = NEXT_INSN (i2);
+ temp_insn
+ && (this_basic_block->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
+ || BB_HEAD (this_basic_block) != temp_insn);
+ temp_insn = NEXT_INSN (temp_insn))
+ if (temp_insn != i3 && NONDEBUG_INSN_P (temp_insn))
+ FOR_EACH_LOG_LINK (link, temp_insn)
+ if (link->insn == i2)
+ link->insn = i3;
+
+ if (i3notes)
+ {
+ rtx link = i3notes;
+ while (XEXP (link, 1))
+ link = XEXP (link, 1);
+ XEXP (link, 1) = i2notes;
+ }
+ else
+ i3notes = i2notes;
+ i2notes = 0;
+ }
+
+ LOG_LINKS (i3) = NULL;
+ REG_NOTES (i3) = 0;
+ LOG_LINKS (i2) = NULL;
+ REG_NOTES (i2) = 0;
+
+ if (newi2pat)
+ {
+ if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
+ propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
+ this_basic_block);
+ INSN_CODE (i2) = i2_code_number;
+ PATTERN (i2) = newi2pat;
+ }
+ else
+ {
+ if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
+ propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
+ this_basic_block);
+ SET_INSN_DELETED (i2);
+ }
+
+ if (i1)
+ {
+ LOG_LINKS (i1) = NULL;
+ REG_NOTES (i1) = 0;
+ if (MAY_HAVE_DEBUG_BIND_INSNS)
+ propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
+ this_basic_block);
+ SET_INSN_DELETED (i1);
+ }
+
+ if (i0)
+ {
+ LOG_LINKS (i0) = NULL;
+ REG_NOTES (i0) = 0;
+ if (MAY_HAVE_DEBUG_BIND_INSNS)
+ propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
+ this_basic_block);
+ SET_INSN_DELETED (i0);
+ }
+
+ /* Get death notes for everything that is now used in either I3 or
+ I2 and used to die in a previous insn. If we built two new
+ patterns, move from I1 to I2 then I2 to I3 so that we get the
+ proper movement on registers that I2 modifies. */
+
+ if (i0)
+ from_luid = DF_INSN_LUID (i0);
+ else if (i1)
+ from_luid = DF_INSN_LUID (i1);
+ else
+ from_luid = DF_INSN_LUID (i2);
+ if (newi2pat)
+ move_deaths (newi2pat, NULL_RTX, from_luid, i2, &midnotes);
+ move_deaths (newpat, newi2pat, from_luid, i3, &midnotes);
+
+ /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
+ if (i3notes)
+ distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL,
+ elim_i2, elim_i1, elim_i0);
+ if (i2notes)
+ distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL,
+ elim_i2, elim_i1, elim_i0);
+ if (i1notes)
+ distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL,
+ elim_i2, local_elim_i1, local_elim_i0);
+ if (i0notes)
+ distribute_notes (i0notes, i0, i3, newi2pat ? i2 : NULL,
+ elim_i2, elim_i1, local_elim_i0);
+ if (midnotes)
+ distribute_notes (midnotes, NULL, i3, newi2pat ? i2 : NULL,
+ elim_i2, elim_i1, elim_i0);
+
+ /* Distribute any notes added to I2 or I3 by recog_for_combine. We
+ know these are REG_UNUSED and want them to go to the desired insn,
+ so we always pass it as i3. */
+
+ if (newi2pat && new_i2_notes)
+ distribute_notes (new_i2_notes, i2, i2, NULL, NULL_RTX, NULL_RTX,
+ NULL_RTX);
+
+ if (new_i3_notes)
+ distribute_notes (new_i3_notes, i3, i3, NULL, NULL_RTX, NULL_RTX,
+ NULL_RTX);
+
+ /* If I3DEST was used in I3SRC, it really died in I3. We may need to
+ put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets
+ I3DEST, the death must be somewhere before I2, not I3. If we passed I3
+ in that case, it might delete I2. Similarly for I2 and I1.
+ Show an additional death due to the REG_DEAD note we make here. If
+ we discard it in distribute_notes, we will decrement it again. */
+
+ if (i3dest_killed)
+ {
+ rtx new_note = alloc_reg_note (REG_DEAD, i3dest_killed, NULL_RTX);
+ if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
+ distribute_notes (new_note, NULL, i2, NULL, elim_i2,
+ elim_i1, elim_i0);
+ else
+ distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ elim_i2, elim_i1, elim_i0);
+ }
+
+ if (i2dest_in_i2src)
+ {
+ rtx new_note = alloc_reg_note (REG_DEAD, i2dest, NULL_RTX);
+ if (newi2pat && reg_set_p (i2dest, newi2pat))
+ distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ NULL_RTX, NULL_RTX);
+ else
+ distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
+ }
+
+ if (i1dest_in_i1src)
+ {
+ rtx new_note = alloc_reg_note (REG_DEAD, i1dest, NULL_RTX);
+ if (newi2pat && reg_set_p (i1dest, newi2pat))
+ distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ NULL_RTX, NULL_RTX);
+ else
+ distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
+ }
+
+ if (i0dest_in_i0src)
+ {
+ rtx new_note = alloc_reg_note (REG_DEAD, i0dest, NULL_RTX);
+ if (newi2pat && reg_set_p (i0dest, newi2pat))
+ distribute_notes (new_note, NULL, i2, NULL, NULL_RTX,
+ NULL_RTX, NULL_RTX);
+ else
+ distribute_notes (new_note, NULL, i3, newi2pat ? i2 : NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
+ }
+
+ distribute_links (i3links);
+ distribute_links (i2links);
+ distribute_links (i1links);
+ distribute_links (i0links);
+
+ if (REG_P (i2dest))
+ {
+ struct insn_link *link;
+ rtx_insn *i2_insn = 0;
+ rtx i2_val = 0, set;
+
+ /* The insn that used to set this register doesn't exist, and
+ this life of the register may not exist either. See if one of
+ I3's links points to an insn that sets I2DEST. If it does,
+ that is now the last known value for I2DEST. If we don't update
+ this and I2 set the register to a value that depended on its old
+ contents, we will get confused. If this insn is used, thing
+ will be set correctly in combine_instructions. */
+ FOR_EACH_LOG_LINK (link, i3)
+ if ((set = single_set (link->insn)) != 0
+ && rtx_equal_p (i2dest, SET_DEST (set)))
+ i2_insn = link->insn, i2_val = SET_SRC (set);
+
+ record_value_for_reg (i2dest, i2_insn, i2_val);
+
+ /* If the reg formerly set in I2 died only once and that was in I3,
+ zero its use count so it won't make `reload' do any work. */
+ if (! added_sets_2
+ && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
+ && ! i2dest_in_i2src
+ && REGNO (i2dest) < reg_n_sets_max)
+ INC_REG_N_SETS (REGNO (i2dest), -1);
+ }
+
+ if (i1 && REG_P (i1dest))
+ {
+ struct insn_link *link;
+ rtx_insn *i1_insn = 0;
+ rtx i1_val = 0, set;
+
+ FOR_EACH_LOG_LINK (link, i3)
+ if ((set = single_set (link->insn)) != 0
+ && rtx_equal_p (i1dest, SET_DEST (set)))
+ i1_insn = link->insn, i1_val = SET_SRC (set);
+
+ record_value_for_reg (i1dest, i1_insn, i1_val);
+
+ if (! added_sets_1
+ && ! i1dest_in_i1src
+ && REGNO (i1dest) < reg_n_sets_max)
+ INC_REG_N_SETS (REGNO (i1dest), -1);
+ }
+
+ if (i0 && REG_P (i0dest))
+ {
+ struct insn_link *link;
+ rtx_insn *i0_insn = 0;
+ rtx i0_val = 0, set;
+
+ FOR_EACH_LOG_LINK (link, i3)
+ if ((set = single_set (link->insn)) != 0
+ && rtx_equal_p (i0dest, SET_DEST (set)))
+ i0_insn = link->insn, i0_val = SET_SRC (set);
+
+ record_value_for_reg (i0dest, i0_insn, i0_val);
+
+ if (! added_sets_0
+ && ! i0dest_in_i0src
+ && REGNO (i0dest) < reg_n_sets_max)
+ INC_REG_N_SETS (REGNO (i0dest), -1);
+ }
+
+ /* Update reg_stat[].nonzero_bits et al for any changes that may have
+ been made to this insn. The order is important, because newi2pat
+ can affect nonzero_bits of newpat. */
+ if (newi2pat)
+ note_pattern_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
+ note_pattern_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
+ }
+
+ if (undobuf.other_insn != NULL_RTX)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying other_insn ");
+ dump_insn_slim (dump_file, undobuf.other_insn);
+ }
+ df_insn_rescan (undobuf.other_insn);
+ }
+
+ if (i0 && !(NOTE_P (i0) && (NOTE_KIND (i0) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i0 ");
+ dump_insn_slim (dump_file, i0);
+ }
+ df_insn_rescan (i0);
+ }
+
+ if (i1 && !(NOTE_P (i1) && (NOTE_KIND (i1) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i1 ");
+ dump_insn_slim (dump_file, i1);
+ }
+ df_insn_rescan (i1);
+ }
+
+ if (i2 && !(NOTE_P (i2) && (NOTE_KIND (i2) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i2 ");
+ dump_insn_slim (dump_file, i2);
+ }
+ df_insn_rescan (i2);
+ }
+
+ if (i3 && !(NOTE_P (i3) && (NOTE_KIND (i3) == NOTE_INSN_DELETED)))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "modifying insn i3 ");
+ dump_insn_slim (dump_file, i3);
+ }
+ df_insn_rescan (i3);
+ }
+
+ /* Set new_direct_jump_p if a new return or simple jump instruction
+ has been created. Adjust the CFG accordingly. */
+ if (returnjump_p (i3) || any_uncondjump_p (i3))
+ {
+ *new_direct_jump_p = 1;
+ mark_jump_label (PATTERN (i3), i3, 0);
+ update_cfg_for_uncondjump (i3);
+ }
+
+ if (undobuf.other_insn != NULL_RTX
+ && (returnjump_p (undobuf.other_insn)
+ || any_uncondjump_p (undobuf.other_insn)))
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (undobuf.other_insn);
+ }
+
+ if (GET_CODE (PATTERN (i3)) == TRAP_IF
+ && XEXP (PATTERN (i3), 0) == const1_rtx)
+ {
+ basic_block bb = BLOCK_FOR_INSN (i3);
+ gcc_assert (bb);
+ remove_edge (split_block (bb, i3));
+ emit_barrier_after_bb (bb);
+ *new_direct_jump_p = 1;
+ }
+
+ if (undobuf.other_insn
+ && GET_CODE (PATTERN (undobuf.other_insn)) == TRAP_IF
+ && XEXP (PATTERN (undobuf.other_insn), 0) == const1_rtx)
+ {
+ basic_block bb = BLOCK_FOR_INSN (undobuf.other_insn);
+ gcc_assert (bb);
+ remove_edge (split_block (bb, undobuf.other_insn));
+ emit_barrier_after_bb (bb);
+ *new_direct_jump_p = 1;
+ }
+
+ /* A noop might also need cleaning up of CFG, if it comes from the
+ simplification of a jump. */
+ if (JUMP_P (i3)
+ && GET_CODE (newpat) == SET
+ && SET_SRC (newpat) == pc_rtx
+ && SET_DEST (newpat) == pc_rtx)
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (i3);
+ }
+
+ if (undobuf.other_insn != NULL_RTX
+ && JUMP_P (undobuf.other_insn)
+ && GET_CODE (PATTERN (undobuf.other_insn)) == SET
+ && SET_SRC (PATTERN (undobuf.other_insn)) == pc_rtx
+ && SET_DEST (PATTERN (undobuf.other_insn)) == pc_rtx)
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (undobuf.other_insn);
+ }
+
+ combine_successes++;
+ undo_commit ();
+
+ rtx_insn *ret = newi2pat ? i2 : i3;
+ if (added_links_insn && DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (ret))
+ ret = added_links_insn;
+ if (added_notes_insn && DF_INSN_LUID (added_notes_insn) < DF_INSN_LUID (ret))
+ ret = added_notes_insn;
+
+ return ret;
+}
+
+/* Get a marker for undoing to the current state. */
+
+static void *
+get_undo_marker (void)
+{
+ return undobuf.undos;
+}
+
+/* Undo the modifications up to the marker. */
+
+static void
+undo_to_marker (void *marker)
+{
+ struct undo *undo, *next;
+
+ for (undo = undobuf.undos; undo != marker; undo = next)
+ {
+ gcc_assert (undo);
+
+ next = undo->next;
+ switch (undo->kind)
+ {
+ case UNDO_RTX:
+ *undo->where.r = undo->old_contents.r;
+ break;
+ case UNDO_INT:
+ *undo->where.i = undo->old_contents.i;
+ break;
+ case UNDO_MODE:
+ adjust_reg_mode (*undo->where.r, undo->old_contents.m);
+ break;
+ case UNDO_LINKS:
+ *undo->where.l = undo->old_contents.l;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ undo->next = undobuf.frees;
+ undobuf.frees = undo;
+ }
+
+ undobuf.undos = (struct undo *) marker;
+}
+
+/* Undo all the modifications recorded in undobuf. */
+
+static void
+undo_all (void)
+{
+ undo_to_marker (0);
+}
+
+/* We've committed to accepting the changes we made. Move all
+ of the undos to the free list. */
+
+static void
+undo_commit (void)
+{
+ struct undo *undo, *next;
+
+ for (undo = undobuf.undos; undo; undo = next)
+ {
+ next = undo->next;
+ undo->next = undobuf.frees;
+ undobuf.frees = undo;
+ }
+ undobuf.undos = 0;
+}
+
+/* Find the innermost point within the rtx at LOC, possibly LOC itself,
+ where we have an arithmetic expression and return that point. LOC will
+ be inside INSN.
+
+ try_combine will call this function to see if an insn can be split into
+ two insns. */
+
+static rtx *
+find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
+{
+ rtx x = *loc;
+ enum rtx_code code = GET_CODE (x);
+ rtx *split;
+ unsigned HOST_WIDE_INT len = 0;
+ HOST_WIDE_INT pos = 0;
+ int unsignedp = 0;
+ rtx inner = NULL_RTX;
+ scalar_int_mode mode, inner_mode;
+
+ /* First special-case some codes. */
+ switch (code)
+ {
+ case SUBREG:
+#ifdef INSN_SCHEDULING
+ /* If we are making a paradoxical SUBREG invalid, it becomes a split
+ point. */
+ if (MEM_P (SUBREG_REG (x)))
+ return loc;
+#endif
+ return find_split_point (&SUBREG_REG (x), insn, false);
+
+ case MEM:
+ /* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it
+ using LO_SUM and HIGH. */
+ if (HAVE_lo_sum && (GET_CODE (XEXP (x, 0)) == CONST
+ || GET_CODE (XEXP (x, 0)) == SYMBOL_REF))
+ {
+ machine_mode address_mode = get_address_mode (x);
+
+ SUBST (XEXP (x, 0),
+ gen_rtx_LO_SUM (address_mode,
+ gen_rtx_HIGH (address_mode, XEXP (x, 0)),
+ XEXP (x, 0)));
+ return &XEXP (XEXP (x, 0), 0);
+ }
+
+ /* If we have a PLUS whose second operand is a constant and the
+ address is not valid, perhaps we can split it up using
+ the machine-specific way to split large constants. We use
+ the first pseudo-reg (one of the virtual regs) as a placeholder;
+ it will not remain in the result. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x)))
+ {
+ rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
+ rtx_insn *seq = combine_split_insns (gen_rtx_SET (reg, XEXP (x, 0)),
+ subst_insn);
+
+ /* This should have produced two insns, each of which sets our
+ placeholder. If the source of the second is a valid address,
+ we can put both sources together and make a split point
+ in the middle. */
+
+ if (seq
+ && NEXT_INSN (seq) != NULL_RTX
+ && NEXT_INSN (NEXT_INSN (seq)) == NULL_RTX
+ && NONJUMP_INSN_P (seq)
+ && GET_CODE (PATTERN (seq)) == SET
+ && SET_DEST (PATTERN (seq)) == reg
+ && ! reg_mentioned_p (reg,
+ SET_SRC (PATTERN (seq)))
+ && NONJUMP_INSN_P (NEXT_INSN (seq))
+ && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
+ && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
+ && memory_address_addr_space_p
+ (GET_MODE (x), SET_SRC (PATTERN (NEXT_INSN (seq))),
+ MEM_ADDR_SPACE (x)))
+ {
+ rtx src1 = SET_SRC (PATTERN (seq));
+ rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq)));
+
+ /* Replace the placeholder in SRC2 with SRC1. If we can
+ find where in SRC2 it was placed, that can become our
+ split point and we can replace this address with SRC2.
+ Just try two obvious places. */
+
+ src2 = replace_rtx (src2, reg, src1);
+ split = 0;
+ if (XEXP (src2, 0) == src1)
+ split = &XEXP (src2, 0);
+ else if (GET_RTX_FORMAT (GET_CODE (XEXP (src2, 0)))[0] == 'e'
+ && XEXP (XEXP (src2, 0), 0) == src1)
+ split = &XEXP (XEXP (src2, 0), 0);
+
+ if (split)
+ {
+ SUBST (XEXP (x, 0), src2);
+ return split;
+ }
+ }
+
+ /* If that didn't work and we have a nested plus, like:
+ ((REG1 * CONST1) + REG2) + CONST2 and (REG1 + REG2) + CONST2
+ is valid address, try to split (REG1 * CONST1). */
+ if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+ && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+ && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+ && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+ 0), 0)))))
+ {
+ rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 0);
+ XEXP (XEXP (XEXP (x, 0), 0), 0) = reg;
+ if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x)))
+ {
+ XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+ return &XEXP (XEXP (XEXP (x, 0), 0), 0);
+ }
+ XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+ }
+ else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+ && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+ && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+ && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+ 0), 1)))))
+ {
+ rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 1);
+ XEXP (XEXP (XEXP (x, 0), 0), 1) = reg;
+ if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x)))
+ {
+ XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+ return &XEXP (XEXP (XEXP (x, 0), 0), 1);
+ }
+ XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+ }
+
+ /* If that didn't work, perhaps the first operand is complex and
+ needs to be computed separately, so make a split point there.
+ This will occur on machines that just support REG + CONST
+ and have a constant moved through some previous computation. */
+ if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
+ && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+ return &XEXP (XEXP (x, 0), 0);
+ }
+
+ /* If we have a PLUS whose first operand is complex, try computing it
+ separately by making a split there. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS
+ && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+ MEM_ADDR_SPACE (x))
+ && ! OBJECT_P (XEXP (XEXP (x, 0), 0))
+ && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+ return &XEXP (XEXP (x, 0), 0);
+ break;
+
+ case SET:
+ /* See if we can split SET_SRC as it stands. */
+ split = find_split_point (&SET_SRC (x), insn, true);
+ if (split && split != &SET_SRC (x))
+ return split;
+
+ /* See if we can split SET_DEST as it stands. */
+ split = find_split_point (&SET_DEST (x), insn, false);
+ if (split && split != &SET_DEST (x))
+ return split;
+
+ /* See if this is a bitfield assignment with everything constant. If
+ so, this is an IOR of an AND, so split it into that. */
+ if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (SET_DEST (x), 0)),
+ &inner_mode)
+ && HWI_COMPUTABLE_MODE_P (inner_mode)
+ && CONST_INT_P (XEXP (SET_DEST (x), 1))
+ && CONST_INT_P (XEXP (SET_DEST (x), 2))
+ && CONST_INT_P (SET_SRC (x))
+ && ((INTVAL (XEXP (SET_DEST (x), 1))
+ + INTVAL (XEXP (SET_DEST (x), 2)))
+ <= GET_MODE_PRECISION (inner_mode))
+ && ! side_effects_p (XEXP (SET_DEST (x), 0)))
+ {
+ HOST_WIDE_INT pos = INTVAL (XEXP (SET_DEST (x), 2));
+ unsigned HOST_WIDE_INT len = INTVAL (XEXP (SET_DEST (x), 1));
+ rtx dest = XEXP (SET_DEST (x), 0);
+ unsigned HOST_WIDE_INT mask = (HOST_WIDE_INT_1U << len) - 1;
+ unsigned HOST_WIDE_INT src = INTVAL (SET_SRC (x)) & mask;
+ rtx or_mask;
+
+ if (BITS_BIG_ENDIAN)
+ pos = GET_MODE_PRECISION (inner_mode) - len - pos;
+
+ or_mask = gen_int_mode (src << pos, inner_mode);
+ if (src == mask)
+ SUBST (SET_SRC (x),
+ simplify_gen_binary (IOR, inner_mode, dest, or_mask));
+ else
+ {
+ rtx negmask = gen_int_mode (~(mask << pos), inner_mode);
+ SUBST (SET_SRC (x),
+ simplify_gen_binary (IOR, inner_mode,
+ simplify_gen_binary (AND, inner_mode,
+ dest, negmask),
+ or_mask));
+ }
+
+ SUBST (SET_DEST (x), dest);
+
+ split = find_split_point (&SET_SRC (x), insn, true);
+ if (split && split != &SET_SRC (x))
+ return split;
+ }
+
+ /* Otherwise, see if this is an operation that we can split into two.
+ If so, try to split that. */
+ code = GET_CODE (SET_SRC (x));
+
+ switch (code)
+ {
+ case AND:
+ /* If we are AND'ing with a large constant that is only a single
+ bit and the result is only being used in a context where we
+ need to know if it is zero or nonzero, replace it with a bit
+ extraction. This will avoid the large constant, which might
+ have taken more than one insn to make. If the constant were
+ not a valid argument to the AND but took only one insn to make,
+ this is no worse, but if it took more than one insn, it will
+ be better. */
+
+ if (CONST_INT_P (XEXP (SET_SRC (x), 1))
+ && REG_P (XEXP (SET_SRC (x), 0))
+ && (pos = exact_log2 (UINTVAL (XEXP (SET_SRC (x), 1)))) >= 7
+ && REG_P (SET_DEST (x))
+ && (split = find_single_use (SET_DEST (x), insn, NULL)) != 0
+ && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
+ && XEXP (*split, 0) == SET_DEST (x)
+ && XEXP (*split, 1) == const0_rtx)
+ {
+ rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
+ XEXP (SET_SRC (x), 0),
+ pos, NULL_RTX, 1, 1, 0, 0);
+ if (extraction != 0)
+ {
+ SUBST (SET_SRC (x), extraction);
+ return find_split_point (loc, insn, false);
+ }
+ }
+ break;
+
+ case NE:
+ /* If STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+ is known to be on, this can be converted into a NEG of a shift. */
+ if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
+ && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
+ && ((pos = exact_log2 (nonzero_bits (XEXP (SET_SRC (x), 0),
+ GET_MODE (XEXP (SET_SRC (x),
+ 0))))) >= 1))
+ {
+ machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
+ rtx pos_rtx = gen_int_shift_amount (mode, pos);
+ SUBST (SET_SRC (x),
+ gen_rtx_NEG (mode,
+ gen_rtx_LSHIFTRT (mode,
+ XEXP (SET_SRC (x), 0),
+ pos_rtx)));
+
+ split = find_split_point (&SET_SRC (x), insn, true);
+ if (split && split != &SET_SRC (x))
+ return split;
+ }
+ break;
+
+ case SIGN_EXTEND:
+ inner = XEXP (SET_SRC (x), 0);
+
+ /* We can't optimize if either mode is a partial integer
+ mode as we don't know how many bits are significant
+ in those modes. */
+ if (!is_int_mode (GET_MODE (inner), &inner_mode)
+ || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+ break;
+
+ pos = 0;
+ len = GET_MODE_PRECISION (inner_mode);
+ unsignedp = 0;
+ break;
+
+ case SIGN_EXTRACT:
+ case ZERO_EXTRACT:
+ if (is_a <scalar_int_mode> (GET_MODE (XEXP (SET_SRC (x), 0)),
+ &inner_mode)
+ && CONST_INT_P (XEXP (SET_SRC (x), 1))
+ && CONST_INT_P (XEXP (SET_SRC (x), 2)))
+ {
+ inner = XEXP (SET_SRC (x), 0);
+ len = INTVAL (XEXP (SET_SRC (x), 1));
+ pos = INTVAL (XEXP (SET_SRC (x), 2));
+
+ if (BITS_BIG_ENDIAN)
+ pos = GET_MODE_PRECISION (inner_mode) - len - pos;
+ unsignedp = (code == ZERO_EXTRACT);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (len
+ && known_subrange_p (pos, len,
+ 0, GET_MODE_PRECISION (GET_MODE (inner)))
+ && is_a <scalar_int_mode> (GET_MODE (SET_SRC (x)), &mode))
+ {
+ /* For unsigned, we have a choice of a shift followed by an
+ AND or two shifts. Use two shifts for field sizes where the
+ constant might be too large. We assume here that we can
+ always at least get 8-bit constants in an AND insn, which is
+ true for every current RISC. */
+
+ if (unsignedp && len <= 8)
+ {
+ unsigned HOST_WIDE_INT mask
+ = (HOST_WIDE_INT_1U << len) - 1;
+ rtx pos_rtx = gen_int_shift_amount (mode, pos);
+ SUBST (SET_SRC (x),
+ gen_rtx_AND (mode,
+ gen_rtx_LSHIFTRT
+ (mode, gen_lowpart (mode, inner), pos_rtx),
+ gen_int_mode (mask, mode)));
+
+ split = find_split_point (&SET_SRC (x), insn, true);
+ if (split && split != &SET_SRC (x))
+ return split;
+ }
+ else
+ {
+ int left_bits = GET_MODE_PRECISION (mode) - len - pos;
+ int right_bits = GET_MODE_PRECISION (mode) - len;
+ SUBST (SET_SRC (x),
+ gen_rtx_fmt_ee
+ (unsignedp ? LSHIFTRT : ASHIFTRT, mode,
+ gen_rtx_ASHIFT (mode,
+ gen_lowpart (mode, inner),
+ gen_int_shift_amount (mode, left_bits)),
+ gen_int_shift_amount (mode, right_bits)));
+
+ split = find_split_point (&SET_SRC (x), insn, true);
+ if (split && split != &SET_SRC (x))
+ return split;
+ }
+ }
+
+ /* See if this is a simple operation with a constant as the second
+ operand. It might be that this constant is out of range and hence
+ could be used as a split point. */
+ if (BINARY_P (SET_SRC (x))
+ && CONSTANT_P (XEXP (SET_SRC (x), 1))
+ && (OBJECT_P (XEXP (SET_SRC (x), 0))
+ || (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (SET_SRC (x), 0))))))
+ return &XEXP (SET_SRC (x), 1);
+
+ /* Finally, see if this is a simple operation with its first operand
+ not in a register. The operation might require this operand in a
+ register, so return it as a split point. We can always do this
+ because if the first operand were another operation, we would have
+ already found it as a split point. */
+ if ((BINARY_P (SET_SRC (x)) || UNARY_P (SET_SRC (x)))
+ && ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
+ return &XEXP (SET_SRC (x), 0);
+
+ return 0;
+
+ case AND:
+ case IOR:
+ /* We write NOR as (and (not A) (not B)), but if we don't have a NOR,
+ it is better to write this as (not (ior A B)) so we can split it.
+ Similarly for IOR. */
+ if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT)
+ {
+ SUBST (*loc,
+ gen_rtx_NOT (GET_MODE (x),
+ gen_rtx_fmt_ee (code == IOR ? AND : IOR,
+ GET_MODE (x),
+ XEXP (XEXP (x, 0), 0),
+ XEXP (XEXP (x, 1), 0))));
+ return find_split_point (loc, insn, set_src);
+ }
+
+ /* Many RISC machines have a large set of logical insns. If the
+ second operand is a NOT, put it first so we will try to split the
+ other operand first. */
+ if (GET_CODE (XEXP (x, 1)) == NOT)
+ {
+ rtx tem = XEXP (x, 0);
+ SUBST (XEXP (x, 0), XEXP (x, 1));
+ SUBST (XEXP (x, 1), tem);
+ }
+ break;
+
+ case PLUS:
+ case MINUS:
+ /* Canonicalization can produce (minus A (mult B C)), where C is a
+ constant. It may be better to try splitting (plus (mult B -C) A)
+ instead if this isn't a multiply by a power of two. */
+ if (set_src && code == MINUS && GET_CODE (XEXP (x, 1)) == MULT
+ && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
+ && !pow2p_hwi (INTVAL (XEXP (XEXP (x, 1), 1))))
+ {
+ machine_mode mode = GET_MODE (x);
+ unsigned HOST_WIDE_INT this_int = INTVAL (XEXP (XEXP (x, 1), 1));
+ HOST_WIDE_INT other_int = trunc_int_for_mode (-this_int, mode);
+ SUBST (*loc, gen_rtx_PLUS (mode,
+ gen_rtx_MULT (mode,
+ XEXP (XEXP (x, 1), 0),
+ gen_int_mode (other_int,
+ mode)),
+ XEXP (x, 0)));
+ return find_split_point (loc, insn, set_src);
+ }
+
+ /* Split at a multiply-accumulate instruction. However if this is
+ the SET_SRC, we likely do not have such an instruction and it's
+ worthless to try this split. */
+ if (!set_src
+ && (GET_CODE (XEXP (x, 0)) == MULT
+ || (GET_CODE (XEXP (x, 0)) == ASHIFT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
+ return loc;
+
+ default:
+ break;
+ }
+
+ /* Otherwise, select our actions depending on our rtx class. */
+ switch (GET_RTX_CLASS (code))
+ {
+ case RTX_BITFIELD_OPS: /* This is ZERO_EXTRACT and SIGN_EXTRACT. */
+ case RTX_TERNARY:
+ split = find_split_point (&XEXP (x, 2), insn, false);
+ if (split)
+ return split;
+ /* fall through */
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ split = find_split_point (&XEXP (x, 1), insn, false);
+ if (split)
+ return split;
+ /* fall through */
+ case RTX_UNARY:
+ /* Some machines have (and (shift ...) ...) insns. If X is not
+ an AND, but XEXP (X, 0) is, use it as our split point. */
+ if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
+ return &XEXP (x, 0);
+
+ split = find_split_point (&XEXP (x, 0), insn, false);
+ if (split)
+ return split;
+ return loc;
+
+ default:
+ /* Otherwise, we don't have a split point. */
+ return 0;
+ }
+}
+
+/* Throughout X, replace FROM with TO, and return the result.
+ The result is TO if X is FROM;
+ otherwise the result is X, but its contents may have been modified.
+ If they were modified, a record was made in undobuf so that
+ undo_all will (among other things) return X to its original state.
+
+ If the number of changes necessary is too much to record to undo,
+ the excess changes are not made, so the result is invalid.
+ The changes already made can still be undone.
+ undobuf.num_undo is incremented for such changes, so by testing that
+ the caller can tell whether the result is valid.
+
+ `n_occurrences' is incremented each time FROM is replaced.
+
+ IN_DEST is nonzero if we are processing the SET_DEST of a SET.
+
+ IN_COND is nonzero if we are at the top level of a condition.
+
+ UNIQUE_COPY is nonzero if each substitution must be unique. We do this
+ by copying if `n_occurrences' is nonzero. */
+
+static rtx
+subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
+{
+ enum rtx_code code = GET_CODE (x);
+ machine_mode op0_mode = VOIDmode;
+ const char *fmt;
+ int len, i;
+ rtx new_rtx;
+
+/* Two expressions are equal if they are identical copies of a shared
+ RTX or if they are both registers with the same register number
+ and mode. */
+
+#define COMBINE_RTX_EQUAL_P(X,Y) \
+ ((X) == (Y) \
+ || (REG_P (X) && REG_P (Y) \
+ && REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y)))
+
+ /* Do not substitute into clobbers of regs -- this will never result in
+ valid RTL. */
+ if (GET_CODE (x) == CLOBBER && REG_P (XEXP (x, 0)))
+ return x;
+
+ if (! in_dest && COMBINE_RTX_EQUAL_P (x, from))
+ {
+ n_occurrences++;
+ return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to);
+ }
+
+ /* If X and FROM are the same register but different modes, they
+ will not have been seen as equal above. However, the log links code
+ will make a LOG_LINKS entry for that case. If we do nothing, we
+ will try to rerecognize our original insn and, when it succeeds,
+ we will delete the feeding insn, which is incorrect.
+
+ So force this insn not to match in this (rare) case. */
+ if (! in_dest && code == REG && REG_P (from)
+ && reg_overlap_mentioned_p (x, from))
+ return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+
+ /* If this is an object, we are done unless it is a MEM or LO_SUM, both
+ of which may contain things that can be combined. */
+ if (code != MEM && code != LO_SUM && OBJECT_P (x))
+ return x;
+
+ /* It is possible to have a subexpression appear twice in the insn.
+ Suppose that FROM is a register that appears within TO.
+ Then, after that subexpression has been scanned once by `subst',
+ the second time it is scanned, TO may be found. If we were
+ to scan TO here, we would find FROM within it and create a
+ self-referent rtl structure which is completely wrong. */
+ if (COMBINE_RTX_EQUAL_P (x, to))
+ return to;
+
+ /* Parallel asm_operands need special attention because all of the
+ inputs are shared across the arms. Furthermore, unsharing the
+ rtl results in recognition failures. Failure to handle this case
+ specially can result in circular rtl.
+
+ Solve this by doing a normal pass across the first entry of the
+ parallel, and only processing the SET_DESTs of the subsequent
+ entries. Ug. */
+
+ if (code == PARALLEL
+ && GET_CODE (XVECEXP (x, 0, 0)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
+ {
+ new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, 0, unique_copy);
+
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
+
+ SUBST (XVECEXP (x, 0, 0), new_rtx);
+
+ for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
+ {
+ rtx dest = SET_DEST (XVECEXP (x, 0, i));
+
+ if (!REG_P (dest) && GET_CODE (dest) != PC)
+ {
+ new_rtx = subst (dest, from, to, 0, 0, unique_copy);
+
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
+
+ SUBST (SET_DEST (XVECEXP (x, 0, i)), new_rtx);
+ }
+ }
+ }
+ else
+ {
+ len = GET_RTX_LENGTH (code);
+ fmt = GET_RTX_FORMAT (code);
+
+ /* We don't need to process a SET_DEST that is a register or PC, so
+ set up to skip this common case. All other cases where we want
+ to suppress replacing something inside a SET_SRC are handled via
+ the IN_DEST operand. */
+ if (code == SET
+ && (REG_P (SET_DEST (x))
+ || GET_CODE (SET_DEST (x)) == PC))
+ fmt = "ie";
+
+ /* Trying to simplify the operands of a widening MULT is not likely
+ to create RTL matching a machine insn. */
+ if (code == MULT
+ && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
+ && (GET_CODE (XEXP (x, 1)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
+ && REG_P (XEXP (XEXP (x, 0), 0))
+ && REG_P (XEXP (XEXP (x, 1), 0))
+ && from == to)
+ return x;
+
+
+ /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+ constant. */
+ if (fmt[0] == 'e')
+ op0_mode = GET_MODE (XEXP (x, 0));
+
+ for (i = 0; i < len; i++)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
+ {
+ new_rtx = (unique_copy && n_occurrences
+ ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ {
+ new_rtx = subst (XVECEXP (x, i, j), from, to, 0, 0,
+ unique_copy);
+
+ /* If this substitution failed, this whole thing
+ fails. */
+ if (GET_CODE (new_rtx) == CLOBBER
+ && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
+ }
+
+ SUBST (XVECEXP (x, i, j), new_rtx);
+ }
+ }
+ else if (fmt[i] == 'e')
+ {
+ /* If this is a register being set, ignore it. */
+ new_rtx = XEXP (x, i);
+ if (in_dest
+ && i == 0
+ && (((code == SUBREG || code == ZERO_EXTRACT)
+ && REG_P (new_rtx))
+ || code == STRICT_LOW_PART))
+ ;
+
+ else if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ {
+ /* In general, don't install a subreg involving two
+ modes not tieable. It can worsen register
+ allocation, and can even make invalid reload
+ insns, since the reg inside may need to be copied
+ from in the outside mode, and that may be invalid
+ if it is an fp reg copied in integer mode.
+
+ We allow an exception to this: It is valid if
+ it is inside another SUBREG and the mode of that
+ SUBREG and the mode of the inside of TO is
+ tieable. */
+
+ if (GET_CODE (to) == SUBREG
+ && !targetm.modes_tieable_p (GET_MODE (to),
+ GET_MODE (SUBREG_REG (to)))
+ && ! (code == SUBREG
+ && (targetm.modes_tieable_p
+ (GET_MODE (x), GET_MODE (SUBREG_REG (to))))))
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+
+ if (code == SUBREG
+ && REG_P (to)
+ && REGNO (to) < FIRST_PSEUDO_REGISTER
+ && simplify_subreg_regno (REGNO (to), GET_MODE (to),
+ SUBREG_BYTE (x),
+ GET_MODE (x)) < 0)
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+
+ new_rtx = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ /* If we are in a SET_DEST, suppress most cases unless we
+ have gone inside a MEM, in which case we want to
+ simplify the address. We assume here that things that
+ are actually part of the destination have their inner
+ parts in the first expression. This is true for SUBREG,
+ STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
+ things aside from REG and MEM that should appear in a
+ SET_DEST. */
+ new_rtx = subst (XEXP (x, i), from, to,
+ (((in_dest
+ && (code == SUBREG || code == STRICT_LOW_PART
+ || code == ZERO_EXTRACT))
+ || code == SET)
+ && i == 0),
+ code == IF_THEN_ELSE && i == 0,
+ unique_copy);
+
+ /* If we found that we will have to reject this combination,
+ indicate that by returning the CLOBBER ourselves, rather than
+ an expression containing it. This will speed things up as
+ well as prevent accidents where two CLOBBERs are considered
+ to be equal, thus producing an incorrect simplification. */
+
+ if (GET_CODE (new_rtx) == CLOBBER && XEXP (new_rtx, 0) == const0_rtx)
+ return new_rtx;
+
+ if (GET_CODE (x) == SUBREG && CONST_SCALAR_INT_P (new_rtx))
+ {
+ machine_mode mode = GET_MODE (x);
+
+ x = simplify_subreg (GET_MODE (x), new_rtx,
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
+ if (! x)
+ x = gen_rtx_CLOBBER (mode, const0_rtx);
+ }
+ else if (CONST_SCALAR_INT_P (new_rtx)
+ && (GET_CODE (x) == ZERO_EXTEND
+ || GET_CODE (x) == SIGN_EXTEND
+ || GET_CODE (x) == FLOAT
+ || GET_CODE (x) == UNSIGNED_FLOAT))
+ {
+ x = simplify_unary_operation (GET_CODE (x), GET_MODE (x),
+ new_rtx,
+ GET_MODE (XEXP (x, 0)));
+ if (!x)
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+ }
+ else
+ SUBST (XEXP (x, i), new_rtx);
+ }
+ }
+ }
+
+ /* Check if we are loading something from the constant pool via float
+ extension; in this case we would undo compress_float_constant
+ optimization and degenerate constant load to an immediate value. */
+ if (GET_CODE (x) == FLOAT_EXTEND
+ && MEM_P (XEXP (x, 0))
+ && MEM_READONLY_P (XEXP (x, 0)))
+ {
+ rtx tmp = avoid_constant_pool_reference (x);
+ if (x != tmp)
+ return x;
+ }
+
+ /* Try to simplify X. If the simplification changed the code, it is likely
+ that further simplification will help, so loop, but limit the number
+ of repetitions that will be performed. */
+
+ for (i = 0; i < 4; i++)
+ {
+ /* If X is sufficiently simple, don't bother trying to do anything
+ with it. */
+ if (code != CONST_INT && code != REG && code != CLOBBER)
+ x = combine_simplify_rtx (x, op0_mode, in_dest, in_cond);
+
+ if (GET_CODE (x) == code)
+ break;
+
+ code = GET_CODE (x);
+
+ /* We no longer know the original mode of operand 0 since we
+ have changed the form of X) */
+ op0_mode = VOIDmode;
+ }
+
+ return x;
+}
+
+/* If X is a commutative operation whose operands are not in the canonical
+ order, use substitutions to swap them. */
+
+static void
+maybe_swap_commutative_operands (rtx x)
+{
+ if (COMMUTATIVE_ARITH_P (x)
+ && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+ {
+ rtx temp = XEXP (x, 0);
+ SUBST (XEXP (x, 0), XEXP (x, 1));
+ SUBST (XEXP (x, 1), temp);
+ }
+}
+
+/* Simplify X, a piece of RTL. We just operate on the expression at the
+ outer level; call `subst' to simplify recursively. Return the new
+ expression.
+
+ OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero
+ if we are inside a SET_DEST. IN_COND is nonzero if we are at the top level
+ of a condition. */
+
+static rtx
+combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
+ int in_cond)
+{
+ enum rtx_code code = GET_CODE (x);
+ machine_mode mode = GET_MODE (x);
+ scalar_int_mode int_mode;
+ rtx temp;
+ int i;
+
+ /* If this is a commutative operation, put a constant last and a complex
+ expression first. We don't need to do this for comparisons here. */
+ maybe_swap_commutative_operands (x);
+
+ /* Try to fold this expression in case we have constants that weren't
+ present before. */
+ temp = 0;
+ switch (GET_RTX_CLASS (code))
+ {
+ case RTX_UNARY:
+ if (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (XEXP (x, 0));
+ temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode);
+ break;
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ {
+ machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
+ if (cmp_mode == VOIDmode)
+ {
+ cmp_mode = GET_MODE (XEXP (x, 1));
+ if (cmp_mode == VOIDmode)
+ cmp_mode = op0_mode;
+ }
+ temp = simplify_relational_operation (code, mode, cmp_mode,
+ XEXP (x, 0), XEXP (x, 1));
+ }
+ break;
+ case RTX_COMM_ARITH:
+ case RTX_BIN_ARITH:
+ temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
+ break;
+ case RTX_BITFIELD_OPS:
+ case RTX_TERNARY:
+ temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0),
+ XEXP (x, 1), XEXP (x, 2));
+ break;
+ default:
+ break;
+ }
+
+ if (temp)
+ {
+ x = temp;
+ code = GET_CODE (temp);
+ op0_mode = VOIDmode;
+ mode = GET_MODE (temp);
+ }
+
+ /* If this is a simple operation applied to an IF_THEN_ELSE, try
+ applying it to the arms of the IF_THEN_ELSE. This often simplifies
+ things. Check for cases where both arms are testing the same
+ condition.
+
+ Don't do anything if all operands are very simple. */
+
+ if ((BINARY_P (x)
+ && ((!OBJECT_P (XEXP (x, 0))
+ && ! (GET_CODE (XEXP (x, 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))
+ || (!OBJECT_P (XEXP (x, 1))
+ && ! (GET_CODE (XEXP (x, 1)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
+ || (UNARY_P (x)
+ && (!OBJECT_P (XEXP (x, 0))
+ && ! (GET_CODE (XEXP (x, 0)) == SUBREG
+ && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
+ {
+ rtx cond, true_rtx, false_rtx;
+
+ cond = if_then_else_cond (x, &true_rtx, &false_rtx);
+ if (cond != 0
+ /* If everything is a comparison, what we have is highly unlikely
+ to be simpler, so don't use it. */
+ && ! (COMPARISON_P (x)
+ && (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx)))
+ /* Similarly, if we end up with one of the expressions the same
+ as the original, it is certainly not simpler. */
+ && ! rtx_equal_p (x, true_rtx)
+ && ! rtx_equal_p (x, false_rtx))
+ {
+ rtx cop1 = const0_rtx;
+ enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
+
+ if (cond_code == NE && COMPARISON_P (cond))
+ return x;
+
+ /* Simplify the alternative arms; this may collapse the true and
+ false arms to store-flag values. Be careful to use copy_rtx
+ here since true_rtx or false_rtx might share RTL with x as a
+ result of the if_then_else_cond call above. */
+ true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0, 0);
+ false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0, 0);
+
+ /* If true_rtx and false_rtx are not general_operands, an if_then_else
+ is unlikely to be simpler. */
+ if (general_operand (true_rtx, VOIDmode)
+ && general_operand (false_rtx, VOIDmode))
+ {
+ enum rtx_code reversed;
+
+ /* Restarting if we generate a store-flag expression will cause
+ us to loop. Just drop through in this case. */
+
+ /* If the result values are STORE_FLAG_VALUE and zero, we can
+ just make the comparison operation. */
+ if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
+ x = simplify_gen_relational (cond_code, mode, VOIDmode,
+ cond, cop1);
+ else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
+ && ((reversed = reversed_comparison_code_parts
+ (cond_code, cond, cop1, NULL))
+ != UNKNOWN))
+ x = simplify_gen_relational (reversed, mode, VOIDmode,
+ cond, cop1);
+
+ /* Likewise, we can make the negate of a comparison operation
+ if the result values are - STORE_FLAG_VALUE and zero. */
+ else if (CONST_INT_P (true_rtx)
+ && INTVAL (true_rtx) == - STORE_FLAG_VALUE
+ && false_rtx == const0_rtx)
+ x = simplify_gen_unary (NEG, mode,
+ simplify_gen_relational (cond_code,
+ mode, VOIDmode,
+ cond, cop1),
+ mode);
+ else if (CONST_INT_P (false_rtx)
+ && INTVAL (false_rtx) == - STORE_FLAG_VALUE
+ && true_rtx == const0_rtx
+ && ((reversed = reversed_comparison_code_parts
+ (cond_code, cond, cop1, NULL))
+ != UNKNOWN))
+ x = simplify_gen_unary (NEG, mode,
+ simplify_gen_relational (reversed,
+ mode, VOIDmode,
+ cond, cop1),
+ mode);
+
+ code = GET_CODE (x);
+ op0_mode = VOIDmode;
+ }
+ }
+ }
+
+ /* First see if we can apply the inverse distributive law. */
+ if (code == PLUS || code == MINUS
+ || code == AND || code == IOR || code == XOR)
+ {
+ x = apply_distributive_law (x);
+ code = GET_CODE (x);
+ op0_mode = VOIDmode;
+ }
+
+ /* If CODE is an associative operation not otherwise handled, see if we
+ can associate some operands. This can win if they are constants or
+ if they are logically related (i.e. (a & b) & a). */
+ if ((code == PLUS || code == MINUS || code == MULT || code == DIV
+ || code == AND || code == IOR || code == XOR
+ || code == SMAX || code == SMIN || code == UMAX || code == UMIN)
+ && ((INTEGRAL_MODE_P (mode) && code != DIV)
+ || (flag_associative_math && FLOAT_MODE_P (mode))))
+ {
+ if (GET_CODE (XEXP (x, 0)) == code)
+ {
+ rtx other = XEXP (XEXP (x, 0), 0);
+ rtx inner_op0 = XEXP (XEXP (x, 0), 1);
+ rtx inner_op1 = XEXP (x, 1);
+ rtx inner;
+
+ /* Make sure we pass the constant operand if any as the second
+ one if this is a commutative operation. */
+ if (CONSTANT_P (inner_op0) && COMMUTATIVE_ARITH_P (x))
+ std::swap (inner_op0, inner_op1);
+ inner = simplify_binary_operation (code == MINUS ? PLUS
+ : code == DIV ? MULT
+ : code,
+ mode, inner_op0, inner_op1);
+
+ /* For commutative operations, try the other pair if that one
+ didn't simplify. */
+ if (inner == 0 && COMMUTATIVE_ARITH_P (x))
+ {
+ other = XEXP (XEXP (x, 0), 1);
+ inner = simplify_binary_operation (code, mode,
+ XEXP (XEXP (x, 0), 0),
+ XEXP (x, 1));
+ }
+
+ if (inner)
+ return simplify_gen_binary (code, mode, other, inner);
+ }
+ }
+
+ /* A little bit of algebraic simplification here. */
+ switch (code)
+ {
+ case MEM:
+ /* Ensure that our address has any ASHIFTs converted to MULT in case
+ address-recognizing predicates are called later. */
+ temp = make_compound_operation (XEXP (x, 0), MEM);
+ SUBST (XEXP (x, 0), temp);
+ break;
+
+ case SUBREG:
+ if (op0_mode == VOIDmode)
+ op0_mode = GET_MODE (SUBREG_REG (x));
+
+ /* See if this can be moved to simplify_subreg. */
+ if (CONSTANT_P (SUBREG_REG (x))
+ && known_eq (subreg_lowpart_offset (mode, op0_mode), SUBREG_BYTE (x))
+ /* Don't call gen_lowpart if the inner mode
+ is VOIDmode and we cannot simplify it, as SUBREG without
+ inner mode is invalid. */
+ && (GET_MODE (SUBREG_REG (x)) != VOIDmode
+ || gen_lowpart_common (mode, SUBREG_REG (x))))
+ return gen_lowpart (mode, SUBREG_REG (x));
+
+ if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
+ break;
+ {
+ rtx temp;
+ temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
+ SUBREG_BYTE (x));
+ if (temp)
+ return temp;
+
+ /* If op is known to have all lower bits zero, the result is zero. */
+ scalar_int_mode int_mode, int_op0_mode;
+ if (!in_dest
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && is_a <scalar_int_mode> (op0_mode, &int_op0_mode)
+ && (GET_MODE_PRECISION (int_mode)
+ < GET_MODE_PRECISION (int_op0_mode))
+ && known_eq (subreg_lowpart_offset (int_mode, int_op0_mode),
+ SUBREG_BYTE (x))
+ && HWI_COMPUTABLE_MODE_P (int_op0_mode)
+ && ((nonzero_bits (SUBREG_REG (x), int_op0_mode)
+ & GET_MODE_MASK (int_mode)) == 0)
+ && !side_effects_p (SUBREG_REG (x)))
+ return CONST0_RTX (int_mode);
+ }
+
+ /* Don't change the mode of the MEM if that would change the meaning
+ of the address. */
+ if (MEM_P (SUBREG_REG (x))
+ && (MEM_VOLATILE_P (SUBREG_REG (x))
+ || mode_dependent_address_p (XEXP (SUBREG_REG (x), 0),
+ MEM_ADDR_SPACE (SUBREG_REG (x)))))
+ return gen_rtx_CLOBBER (mode, const0_rtx);
+
+ /* Note that we cannot do any narrowing for non-constants since
+ we might have been counting on using the fact that some bits were
+ zero. We now do this in the SET. */
+
+ break;
+
+ case NEG:
+ temp = expand_compound_operation (XEXP (x, 0));
+
+ /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
+ replaced by (lshiftrt X C). This will convert
+ (neg (sign_extract X 1 Y)) to (zero_extract X 1 Y). */
+
+ if (GET_CODE (temp) == ASHIFTRT
+ && CONST_INT_P (XEXP (temp, 1))
+ && INTVAL (XEXP (temp, 1)) == GET_MODE_UNIT_PRECISION (mode) - 1)
+ return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (temp, 0),
+ INTVAL (XEXP (temp, 1)));
+
+ /* If X has only a single bit that might be nonzero, say, bit I, convert
+ (neg X) to (ashiftrt (ashift X C-I) C-I) where C is the bitsize of
+ MODE minus 1. This will convert (neg (zero_extract X 1 Y)) to
+ (sign_extract X 1 Y). But only do this if TEMP isn't a register
+ or a SUBREG of one since we'd be making the expression more
+ complex if it was just a register. */
+
+ if (!REG_P (temp)
+ && ! (GET_CODE (temp) == SUBREG
+ && REG_P (SUBREG_REG (temp)))
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && (i = exact_log2 (nonzero_bits (temp, int_mode))) >= 0)
+ {
+ rtx temp1 = simplify_shift_const
+ (NULL_RTX, ASHIFTRT, int_mode,
+ simplify_shift_const (NULL_RTX, ASHIFT, int_mode, temp,
+ GET_MODE_PRECISION (int_mode) - 1 - i),
+ GET_MODE_PRECISION (int_mode) - 1 - i);
+
+ /* If all we did was surround TEMP with the two shifts, we
+ haven't improved anything, so don't use it. Otherwise,
+ we are better off with TEMP1. */
+ if (GET_CODE (temp1) != ASHIFTRT
+ || GET_CODE (XEXP (temp1, 0)) != ASHIFT
+ || XEXP (XEXP (temp1, 0), 0) != temp)
+ return temp1;
+ }
+ break;
+
+ case TRUNCATE:
+ /* We can't handle truncation to a partial integer mode here
+ because we don't know the real bitsize of the partial
+ integer mode. */
+ if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ break;
+
+ if (HWI_COMPUTABLE_MODE_P (mode))
+ SUBST (XEXP (x, 0),
+ force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
+ GET_MODE_MASK (mode), 0));
+
+ /* We can truncate a constant value and return it. */
+ {
+ poly_int64 c;
+ if (poly_int_rtx_p (XEXP (x, 0), &c))
+ return gen_int_mode (c, mode);
+ }
+
+ /* Similarly to what we do in simplify-rtx.c, a truncate of a register
+ whose value is a comparison can be replaced with a subreg if
+ STORE_FLAG_VALUE permits. */
+ if (HWI_COMPUTABLE_MODE_P (mode)
+ && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
+ && (temp = get_last_value (XEXP (x, 0)))
+ && COMPARISON_P (temp)
+ && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (XEXP (x, 0))))
+ return gen_lowpart (mode, XEXP (x, 0));
+ break;
+
+ case CONST:
+ /* (const (const X)) can become (const X). Do it this way rather than
+ returning the inner CONST since CONST can be shared with a
+ REG_EQUAL note. */
+ if (GET_CODE (XEXP (x, 0)) == CONST)
+ SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+ break;
+
+ case LO_SUM:
+ /* Convert (lo_sum (high FOO) FOO) to FOO. This is necessary so we
+ can add in an offset. find_split_point will split this address up
+ again if it doesn't match. */
+ if (HAVE_lo_sum && GET_CODE (XEXP (x, 0)) == HIGH
+ && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
+ return XEXP (x, 1);
+ break;
+
+ case PLUS:
+ /* (plus (xor (and <foo> (const_int pow2 - 1)) <c>) <-c>)
+ when c is (const_int (pow2 + 1) / 2) is a sign extension of a
+ bit-field and can be replaced by either a sign_extend or a
+ sign_extract. The `and' may be a zero_extend and the two
+ <c>, -<c> constants may be reversed. */
+ if (GET_CODE (XEXP (x, 0)) == XOR
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && INTVAL (XEXP (x, 1)) == -INTVAL (XEXP (XEXP (x, 0), 1))
+ && ((i = exact_log2 (UINTVAL (XEXP (XEXP (x, 0), 1)))) >= 0
+ || (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0)
+ && HWI_COMPUTABLE_MODE_P (int_mode)
+ && ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND
+ && CONST_INT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+ && (UINTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
+ == (HOST_WIDE_INT_1U << (i + 1)) - 1))
+ || (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
+ && known_eq ((GET_MODE_PRECISION
+ (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))),
+ (unsigned int) i + 1))))
+ return simplify_shift_const
+ (NULL_RTX, ASHIFTRT, int_mode,
+ simplify_shift_const (NULL_RTX, ASHIFT, int_mode,
+ XEXP (XEXP (XEXP (x, 0), 0), 0),
+ GET_MODE_PRECISION (int_mode) - (i + 1)),
+ GET_MODE_PRECISION (int_mode) - (i + 1));
+
+ /* If only the low-order bit of X is possibly nonzero, (plus x -1)
+ can become (ashiftrt (ashift (xor x 1) C) C) where C is
+ the bitsize of the mode - 1. This allows simplification of
+ "a = (b & 8) == 0;" */
+ if (XEXP (x, 1) == constm1_rtx
+ && !REG_P (XEXP (x, 0))
+ && ! (GET_CODE (XEXP (x, 0)) == SUBREG
+ && REG_P (SUBREG_REG (XEXP (x, 0))))
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && nonzero_bits (XEXP (x, 0), int_mode) == 1)
+ return simplify_shift_const
+ (NULL_RTX, ASHIFTRT, int_mode,
+ simplify_shift_const (NULL_RTX, ASHIFT, int_mode,
+ gen_rtx_XOR (int_mode, XEXP (x, 0),
+ const1_rtx),
+ GET_MODE_PRECISION (int_mode) - 1),
+ GET_MODE_PRECISION (int_mode) - 1);
+
+ /* If we are adding two things that have no bits in common, convert
+ the addition into an IOR. This will often be further simplified,
+ for example in cases like ((a & 1) + (a & 2)), which can
+ become a & 3. */
+
+ if (HWI_COMPUTABLE_MODE_P (mode)
+ && (nonzero_bits (XEXP (x, 0), mode)
+ & nonzero_bits (XEXP (x, 1), mode)) == 0)
+ {
+ /* Try to simplify the expression further. */
+ rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
+ temp = combine_simplify_rtx (tor, VOIDmode, in_dest, 0);
+
+ /* If we could, great. If not, do not go ahead with the IOR
+ replacement, since PLUS appears in many special purpose
+ address arithmetic instructions. */
+ if (GET_CODE (temp) != CLOBBER
+ && (GET_CODE (temp) != IOR
+ || ((XEXP (temp, 0) != XEXP (x, 0)
+ || XEXP (temp, 1) != XEXP (x, 1))
+ && (XEXP (temp, 0) != XEXP (x, 1)
+ || XEXP (temp, 1) != XEXP (x, 0)))))
+ return temp;
+ }
+
+ /* Canonicalize x + x into x << 1. */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && rtx_equal_p (XEXP (x, 0), XEXP (x, 1))
+ && !side_effects_p (XEXP (x, 0)))
+ return simplify_gen_binary (ASHIFT, mode, XEXP (x, 0), const1_rtx);
+
+ break;
+
+ case MINUS:
+ /* (minus <foo> (and <foo> (const_int -pow2))) becomes
+ (and <foo> (const_int pow2-1)) */
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_CODE (XEXP (x, 1)) == AND
+ && CONST_INT_P (XEXP (XEXP (x, 1), 1))
+ && pow2p_hwi (-UINTVAL (XEXP (XEXP (x, 1), 1)))
+ && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
+ return simplify_and_const_int (NULL_RTX, int_mode, XEXP (x, 0),
+ -INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
+ break;
+
+ case MULT:
+ /* If we have (mult (plus A B) C), apply the distributive law and then
+ the inverse distributive law to see if things simplify. This
+ occurs mostly in addresses, often when unrolling loops. */
+
+ if (GET_CODE (XEXP (x, 0)) == PLUS)
+ {
+ rtx result = distribute_and_simplify_rtx (x, 0);
+ if (result)
+ return result;
+ }
+
+ /* Try simplify a*(b/c) as (a*b)/c. */
+ if (FLOAT_MODE_P (mode) && flag_associative_math
+ && GET_CODE (XEXP (x, 0)) == DIV)
+ {
+ rtx tem = simplify_binary_operation (MULT, mode,
+ XEXP (XEXP (x, 0), 0),
+ XEXP (x, 1));
+ if (tem)
+ return simplify_gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
+ }
+ break;
+
+ case UDIV:
+ /* If this is a divide by a power of two, treat it as a shift if
+ its first operand is a shift. */
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && CONST_INT_P (XEXP (x, 1))
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
+ && (GET_CODE (XEXP (x, 0)) == ASHIFT
+ || GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ || GET_CODE (XEXP (x, 0)) == ASHIFTRT
+ || GET_CODE (XEXP (x, 0)) == ROTATE
+ || GET_CODE (XEXP (x, 0)) == ROTATERT))
+ return simplify_shift_const (NULL_RTX, LSHIFTRT, int_mode,
+ XEXP (x, 0), i);
+ break;
+
+ case EQ: case NE:
+ case GT: case GTU: case GE: case GEU:
+ case LT: case LTU: case LE: case LEU:
+ case UNEQ: case LTGT:
+ case UNGT: case UNGE:
+ case UNLT: case UNLE:
+ case UNORDERED: case ORDERED:
+ /* If the first operand is a condition code, we can't do anything
+ with it. */
+ if (GET_CODE (XEXP (x, 0)) == COMPARE
+ || GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC)
+ {
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+ enum rtx_code new_code;
+
+ if (GET_CODE (op0) == COMPARE)
+ op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
+
+ /* Simplify our comparison, if possible. */
+ new_code = simplify_comparison (code, &op0, &op1);
+
+ /* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X
+ if only the low-order bit is possibly nonzero in X (such as when
+ X is a ZERO_EXTRACT of one bit). Similarly, we can convert EQ to
+ (xor X 1) or (minus 1 X); we use the former. Finally, if X is
+ known to be either 0 or -1, NE becomes a NEG and EQ becomes
+ (plus X 1).
+
+ Remove any ZERO_EXTRACT we made when thinking this was a
+ comparison. It may now be simpler to use, e.g., an AND. If a
+ ZERO_EXTRACT is indeed appropriate, it will be placed back by
+ the call to make_compound_operation in the SET case.
+
+ Don't apply these optimizations if the caller would
+ prefer a comparison rather than a value.
+ E.g., for the condition in an IF_THEN_ELSE most targets need
+ an explicit comparison. */
+
+ if (in_cond)
+ ;
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == NE
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && nonzero_bits (op0, int_mode) == 1)
+ return gen_lowpart (int_mode,
+ expand_compound_operation (op0));
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == NE
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && (num_sign_bit_copies (op0, int_mode)
+ == GET_MODE_PRECISION (int_mode)))
+ {
+ op0 = expand_compound_operation (op0);
+ return simplify_gen_unary (NEG, int_mode,
+ gen_lowpart (int_mode, op0),
+ int_mode);
+ }
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && nonzero_bits (op0, int_mode) == 1)
+ {
+ op0 = expand_compound_operation (op0);
+ return simplify_gen_binary (XOR, int_mode,
+ gen_lowpart (int_mode, op0),
+ const1_rtx);
+ }
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && (num_sign_bit_copies (op0, int_mode)
+ == GET_MODE_PRECISION (int_mode)))
+ {
+ op0 = expand_compound_operation (op0);
+ return plus_constant (int_mode, gen_lowpart (int_mode, op0), 1);
+ }
+
+ /* If STORE_FLAG_VALUE is -1, we have cases similar to
+ those above. */
+ if (in_cond)
+ ;
+
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == NE
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && (num_sign_bit_copies (op0, int_mode)
+ == GET_MODE_PRECISION (int_mode)))
+ return gen_lowpart (int_mode, expand_compound_operation (op0));
+
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == NE
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && nonzero_bits (op0, int_mode) == 1)
+ {
+ op0 = expand_compound_operation (op0);
+ return simplify_gen_unary (NEG, int_mode,
+ gen_lowpart (int_mode, op0),
+ int_mode);
+ }
+
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && (num_sign_bit_copies (op0, int_mode)
+ == GET_MODE_PRECISION (int_mode)))
+ {
+ op0 = expand_compound_operation (op0);
+ return simplify_gen_unary (NOT, int_mode,
+ gen_lowpart (int_mode, op0),
+ int_mode);
+ }
+
+ /* If X is 0/1, (eq X 0) is X-1. */
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ
+ && is_int_mode (mode, &int_mode)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && nonzero_bits (op0, int_mode) == 1)
+ {
+ op0 = expand_compound_operation (op0);
+ return plus_constant (int_mode, gen_lowpart (int_mode, op0), -1);
+ }
+
+ /* If STORE_FLAG_VALUE says to just test the sign bit and X has just
+ one bit that might be nonzero, we can convert (ne x 0) to
+ (ashift x c) where C puts the bit in the sign bit. Remove any
+ AND with STORE_FLAG_VALUE when we are done, since we are only
+ going to test the sign bit. */
+ if (new_code == NE
+ && is_int_mode (mode, &int_mode)
+ && HWI_COMPUTABLE_MODE_P (int_mode)
+ && val_signbit_p (int_mode, STORE_FLAG_VALUE)
+ && op1 == const0_rtx
+ && int_mode == GET_MODE (op0)
+ && (i = exact_log2 (nonzero_bits (op0, int_mode))) >= 0)
+ {
+ x = simplify_shift_const (NULL_RTX, ASHIFT, int_mode,
+ expand_compound_operation (op0),
+ GET_MODE_PRECISION (int_mode) - 1 - i);
+ if (GET_CODE (x) == AND && XEXP (x, 1) == const_true_rtx)
+ return XEXP (x, 0);
+ else
+ return x;
+ }
+
+ /* If the code changed, return a whole new comparison.
+ We also need to avoid using SUBST in cases where
+ simplify_comparison has widened a comparison with a CONST_INT,
+ since in that case the wider CONST_INT may fail the sanity
+ checks in do_SUBST. */
+ if (new_code != code
+ || (CONST_INT_P (op1)
+ && GET_MODE (op0) != GET_MODE (XEXP (x, 0))
+ && GET_MODE (op0) != GET_MODE (XEXP (x, 1))))
+ return gen_rtx_fmt_ee (new_code, mode, op0, op1);
+
+ /* Otherwise, keep this operation, but maybe change its operands.
+ This also converts (ne (compare FOO BAR) 0) to (ne FOO BAR). */
+ SUBST (XEXP (x, 0), op0);
+ SUBST (XEXP (x, 1), op1);
+ }
+ break;
+
+ case IF_THEN_ELSE:
+ return simplify_if_then_else (x);
+
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
+ case ZERO_EXTEND:
+ case SIGN_EXTEND:
+ /* If we are processing SET_DEST, we are done. */
+ if (in_dest)
+ return x;
+
+ return expand_compound_operation (x);
+
+ case SET:
+ return simplify_set (x);
+
+ case AND:
+ case IOR:
+ return simplify_logical (x);
+
+ case ASHIFT:
+ case LSHIFTRT:
+ case ASHIFTRT:
+ case ROTATE:
+ case ROTATERT:
+ /* If this is a shift by a constant amount, simplify it. */
+ if (CONST_INT_P (XEXP (x, 1)))
+ return simplify_shift_const (x, code, mode, XEXP (x, 0),
+ INTVAL (XEXP (x, 1)));
+
+ else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
+ SUBST (XEXP (x, 1),
+ force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
+ (HOST_WIDE_INT_1U
+ << exact_log2 (GET_MODE_UNIT_BITSIZE
+ (GET_MODE (x))))
+ - 1,
+ 0));
+ break;
+ case VEC_SELECT:
+ {
+ rtx trueop0 = XEXP (x, 0);
+ mode = GET_MODE (trueop0);
+ rtx trueop1 = XEXP (x, 1);
+ /* If we select a low-part subreg, return that. */
+ if (vec_series_lowpart_p (GET_MODE (x), mode, trueop1))
+ {
+ rtx new_rtx = lowpart_subreg (GET_MODE (x), trueop0, mode);
+ if (new_rtx != NULL_RTX)
+ return new_rtx;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Simplify X, an IF_THEN_ELSE expression. Return the new expression. */
+
+static rtx
+simplify_if_then_else (rtx x)
+{
+ machine_mode mode = GET_MODE (x);
+ rtx cond = XEXP (x, 0);
+ rtx true_rtx = XEXP (x, 1);
+ rtx false_rtx = XEXP (x, 2);
+ enum rtx_code true_code = GET_CODE (cond);
+ int comparison_p = COMPARISON_P (cond);
+ rtx temp;
+ int i;
+ enum rtx_code false_code;
+ rtx reversed;
+ scalar_int_mode int_mode, inner_mode;
+
+ /* Simplify storing of the truth value. */
+ if (comparison_p && true_rtx == const_true_rtx && false_rtx == const0_rtx)
+ return simplify_gen_relational (true_code, mode, VOIDmode,
+ XEXP (cond, 0), XEXP (cond, 1));
+
+ /* Also when the truth value has to be reversed. */
+ if (comparison_p
+ && true_rtx == const0_rtx && false_rtx == const_true_rtx
+ && (reversed = reversed_comparison (cond, mode)))
+ return reversed;
+
+ /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register used
+ in it is being compared against certain values. Get the true and false
+ comparisons and see if that says anything about the value of each arm. */
+
+ if (comparison_p
+ && ((false_code = reversed_comparison_code (cond, NULL))
+ != UNKNOWN)
+ && REG_P (XEXP (cond, 0)))
+ {
+ HOST_WIDE_INT nzb;
+ rtx from = XEXP (cond, 0);
+ rtx true_val = XEXP (cond, 1);
+ rtx false_val = true_val;
+ int swapped = 0;
+
+ /* If FALSE_CODE is EQ, swap the codes and arms. */
+
+ if (false_code == EQ)
+ {
+ swapped = 1, true_code = EQ, false_code = NE;
+ std::swap (true_rtx, false_rtx);
+ }
+
+ scalar_int_mode from_mode;
+ if (is_a <scalar_int_mode> (GET_MODE (from), &from_mode))
+ {
+ /* If we are comparing against zero and the expression being
+ tested has only a single bit that might be nonzero, that is
+ its value when it is not equal to zero. Similarly if it is
+ known to be -1 or 0. */
+ if (true_code == EQ
+ && true_val == const0_rtx
+ && pow2p_hwi (nzb = nonzero_bits (from, from_mode)))
+ {
+ false_code = EQ;
+ false_val = gen_int_mode (nzb, from_mode);
+ }
+ else if (true_code == EQ
+ && true_val == const0_rtx
+ && (num_sign_bit_copies (from, from_mode)
+ == GET_MODE_PRECISION (from_mode)))
+ {
+ false_code = EQ;
+ false_val = constm1_rtx;
+ }
+ }
+
+ /* Now simplify an arm if we know the value of the register in the
+ branch and it is used in the arm. Be careful due to the potential
+ of locally-shared RTL. */
+
+ if (reg_mentioned_p (from, true_rtx))
+ true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
+ from, true_val),
+ pc_rtx, pc_rtx, 0, 0, 0);
+ if (reg_mentioned_p (from, false_rtx))
+ false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
+ from, false_val),
+ pc_rtx, pc_rtx, 0, 0, 0);
+
+ SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
+ SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
+
+ true_rtx = XEXP (x, 1);
+ false_rtx = XEXP (x, 2);
+ true_code = GET_CODE (cond);
+ }
+
+ /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be
+ reversed, do so to avoid needing two sets of patterns for
+ subtract-and-branch insns. Similarly if we have a constant in the true
+ arm, the false arm is the same as the first operand of the comparison, or
+ the false arm is more complicated than the true arm. */
+
+ if (comparison_p
+ && reversed_comparison_code (cond, NULL) != UNKNOWN
+ && (true_rtx == pc_rtx
+ || (CONSTANT_P (true_rtx)
+ && !CONST_INT_P (false_rtx) && false_rtx != pc_rtx)
+ || true_rtx == const0_rtx
+ || (OBJECT_P (true_rtx) && !OBJECT_P (false_rtx))
+ || (GET_CODE (true_rtx) == SUBREG && OBJECT_P (SUBREG_REG (true_rtx))
+ && !OBJECT_P (false_rtx))
+ || reg_mentioned_p (true_rtx, false_rtx)
+ || rtx_equal_p (false_rtx, XEXP (cond, 0))))
+ {
+ SUBST (XEXP (x, 0), reversed_comparison (cond, GET_MODE (cond)));
+ SUBST (XEXP (x, 1), false_rtx);
+ SUBST (XEXP (x, 2), true_rtx);
+
+ std::swap (true_rtx, false_rtx);
+ cond = XEXP (x, 0);
+
+ /* It is possible that the conditional has been simplified out. */
+ true_code = GET_CODE (cond);
+ comparison_p = COMPARISON_P (cond);
+ }
+
+ /* If the two arms are identical, we don't need the comparison. */
+
+ if (rtx_equal_p (true_rtx, false_rtx) && ! side_effects_p (cond))
+ return true_rtx;
+
+ /* Convert a == b ? b : a to "a". */
+ if (true_code == EQ && ! side_effects_p (cond)
+ && !HONOR_NANS (mode)
+ && rtx_equal_p (XEXP (cond, 0), false_rtx)
+ && rtx_equal_p (XEXP (cond, 1), true_rtx))
+ return false_rtx;
+ else if (true_code == NE && ! side_effects_p (cond)
+ && !HONOR_NANS (mode)
+ && rtx_equal_p (XEXP (cond, 0), true_rtx)
+ && rtx_equal_p (XEXP (cond, 1), false_rtx))
+ return true_rtx;
+
+ /* Look for cases where we have (abs x) or (neg (abs X)). */
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && comparison_p
+ && XEXP (cond, 1) == const0_rtx
+ && GET_CODE (false_rtx) == NEG
+ && rtx_equal_p (true_rtx, XEXP (false_rtx, 0))
+ && rtx_equal_p (true_rtx, XEXP (cond, 0))
+ && ! side_effects_p (true_rtx))
+ switch (true_code)
+ {
+ case GT:
+ case GE:
+ return simplify_gen_unary (ABS, mode, true_rtx, mode);
+ case LT:
+ case LE:
+ return
+ simplify_gen_unary (NEG, mode,
+ simplify_gen_unary (ABS, mode, true_rtx, mode),
+ mode);
+ default:
+ break;
+ }
+
+ /* Look for MIN or MAX. */
+
+ if ((! FLOAT_MODE_P (mode)
+ || (flag_unsafe_math_optimizations
+ && !HONOR_NANS (mode)
+ && !HONOR_SIGNED_ZEROS (mode)))
+ && comparison_p
+ && rtx_equal_p (XEXP (cond, 0), true_rtx)
+ && rtx_equal_p (XEXP (cond, 1), false_rtx)
+ && ! side_effects_p (cond))
+ switch (true_code)
+ {
+ case GE:
+ case GT:
+ return simplify_gen_binary (SMAX, mode, true_rtx, false_rtx);
+ case LE:
+ case LT:
+ return simplify_gen_binary (SMIN, mode, true_rtx, false_rtx);
+ case GEU:
+ case GTU:
+ return simplify_gen_binary (UMAX, mode, true_rtx, false_rtx);
+ case LEU:
+ case LTU:
+ return simplify_gen_binary (UMIN, mode, true_rtx, false_rtx);
+ default:
+ break;
+ }
+
+ /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
+ second operand is zero, this can be done as (OP Z (mult COND C2)) where
+ C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer ZERO_EXTEND or
+ SIGN_EXTEND as long as Z is already extended (so we don't destroy it).
+ We can do this kind of thing in some cases when STORE_FLAG_VALUE is
+ neither 1 or -1, but it isn't worth checking for. */
+
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && comparison_p
+ && is_int_mode (mode, &int_mode)
+ && ! side_effects_p (x))
+ {
+ rtx t = make_compound_operation (true_rtx, SET);
+ rtx f = make_compound_operation (false_rtx, SET);
+ rtx cond_op0 = XEXP (cond, 0);
+ rtx cond_op1 = XEXP (cond, 1);
+ enum rtx_code op = UNKNOWN, extend_op = UNKNOWN;
+ scalar_int_mode m = int_mode;
+ rtx z = 0, c1 = NULL_RTX;
+
+ if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS
+ || GET_CODE (t) == IOR || GET_CODE (t) == XOR
+ || GET_CODE (t) == ASHIFT
+ || GET_CODE (t) == LSHIFTRT || GET_CODE (t) == ASHIFTRT)
+ && rtx_equal_p (XEXP (t, 0), f))
+ c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
+
+ /* If an identity-zero op is commutative, check whether there
+ would be a match if we swapped the operands. */
+ else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR
+ || GET_CODE (t) == XOR)
+ && rtx_equal_p (XEXP (t, 1), f))
+ c1 = XEXP (t, 0), op = GET_CODE (t), z = f;
+ else if (GET_CODE (t) == SIGN_EXTEND
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (t, 0)), &inner_mode)
+ && (GET_CODE (XEXP (t, 0)) == PLUS
+ || GET_CODE (XEXP (t, 0)) == MINUS
+ || GET_CODE (XEXP (t, 0)) == IOR
+ || GET_CODE (XEXP (t, 0)) == XOR
+ || GET_CODE (XEXP (t, 0)) == ASHIFT
+ || GET_CODE (XEXP (t, 0)) == LSHIFTRT
+ || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
+ && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
+ && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
+ && (num_sign_bit_copies (f, GET_MODE (f))
+ > (unsigned int)
+ (GET_MODE_PRECISION (int_mode)
+ - GET_MODE_PRECISION (inner_mode))))
+ {
+ c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
+ extend_op = SIGN_EXTEND;
+ m = inner_mode;
+ }
+ else if (GET_CODE (t) == SIGN_EXTEND
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (t, 0)), &inner_mode)
+ && (GET_CODE (XEXP (t, 0)) == PLUS
+ || GET_CODE (XEXP (t, 0)) == IOR
+ || GET_CODE (XEXP (t, 0)) == XOR)
+ && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
+ && subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
+ && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
+ && (num_sign_bit_copies (f, GET_MODE (f))
+ > (unsigned int)
+ (GET_MODE_PRECISION (int_mode)
+ - GET_MODE_PRECISION (inner_mode))))
+ {
+ c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
+ extend_op = SIGN_EXTEND;
+ m = inner_mode;
+ }
+ else if (GET_CODE (t) == ZERO_EXTEND
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (t, 0)), &inner_mode)
+ && (GET_CODE (XEXP (t, 0)) == PLUS
+ || GET_CODE (XEXP (t, 0)) == MINUS
+ || GET_CODE (XEXP (t, 0)) == IOR
+ || GET_CODE (XEXP (t, 0)) == XOR
+ || GET_CODE (XEXP (t, 0)) == ASHIFT
+ || GET_CODE (XEXP (t, 0)) == LSHIFTRT
+ || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
+ && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
+ && HWI_COMPUTABLE_MODE_P (int_mode)
+ && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
+ && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
+ && ((nonzero_bits (f, GET_MODE (f))
+ & ~GET_MODE_MASK (inner_mode))
+ == 0))
+ {
+ c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
+ extend_op = ZERO_EXTEND;
+ m = inner_mode;
+ }
+ else if (GET_CODE (t) == ZERO_EXTEND
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (t, 0)), &inner_mode)
+ && (GET_CODE (XEXP (t, 0)) == PLUS
+ || GET_CODE (XEXP (t, 0)) == IOR
+ || GET_CODE (XEXP (t, 0)) == XOR)
+ && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
+ && HWI_COMPUTABLE_MODE_P (int_mode)
+ && subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
+ && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
+ && ((nonzero_bits (f, GET_MODE (f))
+ & ~GET_MODE_MASK (inner_mode))
+ == 0))
+ {
+ c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
+ extend_op = ZERO_EXTEND;
+ m = inner_mode;
+ }
+
+ if (z)
+ {
+ machine_mode cm = m;
+ if ((op == ASHIFT || op == LSHIFTRT || op == ASHIFTRT)
+ && GET_MODE (c1) != VOIDmode)
+ cm = GET_MODE (c1);
+ temp = subst (simplify_gen_relational (true_code, cm, VOIDmode,
+ cond_op0, cond_op1),
+ pc_rtx, pc_rtx, 0, 0, 0);
+ temp = simplify_gen_binary (MULT, cm, temp,
+ simplify_gen_binary (MULT, cm, c1,
+ const_true_rtx));
+ temp = subst (temp, pc_rtx, pc_rtx, 0, 0, 0);
+ temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
+
+ if (extend_op != UNKNOWN)
+ temp = simplify_gen_unary (extend_op, int_mode, temp, m);
+
+ return temp;
+ }
+ }
+
+ /* If we have (if_then_else (ne A 0) C1 0) and either A is known to be 0 or
+ 1 and C1 is a single bit or A is known to be 0 or -1 and C1 is the
+ negation of a single bit, we can convert this operation to a shift. We
+ can actually do this more generally, but it doesn't seem worth it. */
+
+ if (true_code == NE
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && XEXP (cond, 1) == const0_rtx
+ && false_rtx == const0_rtx
+ && CONST_INT_P (true_rtx)
+ && ((nonzero_bits (XEXP (cond, 0), int_mode) == 1
+ && (i = exact_log2 (UINTVAL (true_rtx))) >= 0)
+ || ((num_sign_bit_copies (XEXP (cond, 0), int_mode)
+ == GET_MODE_PRECISION (int_mode))
+ && (i = exact_log2 (-UINTVAL (true_rtx))) >= 0)))
+ return
+ simplify_shift_const (NULL_RTX, ASHIFT, int_mode,
+ gen_lowpart (int_mode, XEXP (cond, 0)), i);
+
+ /* (IF_THEN_ELSE (NE A 0) C1 0) is A or a zero-extend of A if the only
+ non-zero bit in A is C1. */
+ if (true_code == NE && XEXP (cond, 1) == const0_rtx
+ && false_rtx == const0_rtx && CONST_INT_P (true_rtx)
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (cond, 0)), &inner_mode)
+ && (UINTVAL (true_rtx) & GET_MODE_MASK (int_mode))
+ == nonzero_bits (XEXP (cond, 0), inner_mode)
+ && (i = exact_log2 (UINTVAL (true_rtx) & GET_MODE_MASK (int_mode))) >= 0)
+ {
+ rtx val = XEXP (cond, 0);
+ if (inner_mode == int_mode)
+ return val;
+ else if (GET_MODE_PRECISION (inner_mode) < GET_MODE_PRECISION (int_mode))
+ return simplify_gen_unary (ZERO_EXTEND, int_mode, val, inner_mode);
+ }
+
+ return x;
+}
+
+/* Simplify X, a SET expression. Return the new expression. */
+
+static rtx
+simplify_set (rtx x)
+{
+ rtx src = SET_SRC (x);
+ rtx dest = SET_DEST (x);
+ machine_mode mode
+ = GET_MODE (src) != VOIDmode ? GET_MODE (src) : GET_MODE (dest);
+ rtx_insn *other_insn;
+ rtx *cc_use;
+ scalar_int_mode int_mode;
+
+ /* (set (pc) (return)) gets written as (return). */
+ if (GET_CODE (dest) == PC && ANY_RETURN_P (src))
+ return src;
+
+ /* Now that we know for sure which bits of SRC we are using, see if we can
+ simplify the expression for the object knowing that we only need the
+ low-order bits. */
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && HWI_COMPUTABLE_MODE_P (mode))
+ {
+ src = force_to_mode (src, mode, HOST_WIDE_INT_M1U, 0);
+ SUBST (SET_SRC (x), src);
+ }
+
+ /* If the source is a COMPARE, look for the use of the comparison result
+ and try to simplify it unless we already have used undobuf.other_insn. */
+ if ((GET_MODE_CLASS (mode) == MODE_CC || GET_CODE (src) == COMPARE)
+ && (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
+ && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
+ && COMPARISON_P (*cc_use)
+ && rtx_equal_p (XEXP (*cc_use, 0), dest))
+ {
+ enum rtx_code old_code = GET_CODE (*cc_use);
+ enum rtx_code new_code;
+ rtx op0, op1, tmp;
+ int other_changed = 0;
+ rtx inner_compare = NULL_RTX;
+ machine_mode compare_mode = GET_MODE (dest);
+
+ if (GET_CODE (src) == COMPARE)
+ {
+ op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+ if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+ {
+ inner_compare = op0;
+ op0 = XEXP (inner_compare, 0), op1 = XEXP (inner_compare, 1);
+ }
+ }
+ else
+ op0 = src, op1 = CONST0_RTX (GET_MODE (src));
+
+ tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
+ op0, op1);
+ if (!tmp)
+ new_code = old_code;
+ else if (!CONSTANT_P (tmp))
+ {
+ new_code = GET_CODE (tmp);
+ op0 = XEXP (tmp, 0);
+ op1 = XEXP (tmp, 1);
+ }
+ else
+ {
+ rtx pat = PATTERN (other_insn);
+ undobuf.other_insn = other_insn;
+ SUBST (*cc_use, tmp);
+
+ /* Attempt to simplify CC user. */
+ if (GET_CODE (pat) == SET)
+ {
+ rtx new_rtx = simplify_rtx (SET_SRC (pat));
+ if (new_rtx != NULL_RTX)
+ SUBST (SET_SRC (pat), new_rtx);
+ }
+
+ /* Convert X into a no-op move. */
+ SUBST (SET_DEST (x), pc_rtx);
+ SUBST (SET_SRC (x), pc_rtx);
+ return x;
+ }
+
+ /* Simplify our comparison, if possible. */
+ new_code = simplify_comparison (new_code, &op0, &op1);
+
+#ifdef SELECT_CC_MODE
+ /* If this machine has CC modes other than CCmode, check to see if we
+ need to use a different CC mode here. */
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+ compare_mode = GET_MODE (op0);
+ else if (inner_compare
+ && GET_MODE_CLASS (GET_MODE (inner_compare)) == MODE_CC
+ && new_code == old_code
+ && op0 == XEXP (inner_compare, 0)
+ && op1 == XEXP (inner_compare, 1))
+ compare_mode = GET_MODE (inner_compare);
+ else
+ compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+
+ /* If the mode changed, we have to change SET_DEST, the mode in the
+ compare, and the mode in the place SET_DEST is used. If SET_DEST is
+ a hard register, just build new versions with the proper mode. If it
+ is a pseudo, we lose unless it is only time we set the pseudo, in
+ which case we can safely change its mode. */
+ if (compare_mode != GET_MODE (dest))
+ {
+ if (can_change_dest_mode (dest, 0, compare_mode))
+ {
+ unsigned int regno = REGNO (dest);
+ rtx new_dest;
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ new_dest = gen_rtx_REG (compare_mode, regno);
+ else
+ {
+ SUBST_MODE (regno_reg_rtx[regno], compare_mode);
+ new_dest = regno_reg_rtx[regno];
+ }
+
+ SUBST (SET_DEST (x), new_dest);
+ SUBST (XEXP (*cc_use, 0), new_dest);
+ other_changed = 1;
+
+ dest = new_dest;
+ }
+ }
+#endif /* SELECT_CC_MODE */
+
+ /* If the code changed, we have to build a new comparison in
+ undobuf.other_insn. */
+ if (new_code != old_code)
+ {
+ int other_changed_previously = other_changed;
+ unsigned HOST_WIDE_INT mask;
+ rtx old_cc_use = *cc_use;
+
+ SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
+ dest, const0_rtx));
+ other_changed = 1;
+
+ /* If the only change we made was to change an EQ into an NE or
+ vice versa, OP0 has only one bit that might be nonzero, and OP1
+ is zero, check if changing the user of the condition code will
+ produce a valid insn. If it won't, we can keep the original code
+ in that insn by surrounding our operation with an XOR. */
+
+ if (((old_code == NE && new_code == EQ)
+ || (old_code == EQ && new_code == NE))
+ && ! other_changed_previously && op1 == const0_rtx
+ && HWI_COMPUTABLE_MODE_P (GET_MODE (op0))
+ && pow2p_hwi (mask = nonzero_bits (op0, GET_MODE (op0))))
+ {
+ rtx pat = PATTERN (other_insn), note = 0;
+
+ if ((recog_for_combine (&pat, other_insn, &note) < 0
+ && ! check_asm_operands (pat)))
+ {
+ *cc_use = old_cc_use;
+ other_changed = 0;
+
+ op0 = simplify_gen_binary (XOR, GET_MODE (op0), op0,
+ gen_int_mode (mask,
+ GET_MODE (op0)));
+ }
+ }
+ }
+
+ if (other_changed)
+ undobuf.other_insn = other_insn;
+
+ /* Don't generate a compare of a CC with 0, just use that CC. */
+ if (GET_MODE (op0) == compare_mode && op1 == const0_rtx)
+ {
+ SUBST (SET_SRC (x), op0);
+ src = SET_SRC (x);
+ }
+ /* Otherwise, if we didn't previously have the same COMPARE we
+ want, create it from scratch. */
+ else if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode
+ || XEXP (src, 0) != op0 || XEXP (src, 1) != op1)
+ {
+ SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1));
+ src = SET_SRC (x);
+ }
+ }
+ else
+ {
+ /* Get SET_SRC in a form where we have placed back any
+ compound expressions. Then do the checks below. */
+ src = make_compound_operation (src, SET);
+ SUBST (SET_SRC (x), src);
+ }
+
+ /* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation,
+ and X being a REG or (subreg (reg)), we may be able to convert this to
+ (set (subreg:m2 x) (op)).
+
+ We can always do this if M1 is narrower than M2 because that means that
+ we only care about the low bits of the result.
+
+ However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
+ perform a narrower operation than requested since the high-order bits will
+ be undefined. On machine where it is defined, this transformation is safe
+ as long as M1 and M2 have the same number of words. */
+
+ if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
+ && !OBJECT_P (SUBREG_REG (src))
+ && (known_equal_after_align_up
+ (GET_MODE_SIZE (GET_MODE (src)),
+ GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))),
+ UNITS_PER_WORD))
+ && (WORD_REGISTER_OPERATIONS || !paradoxical_subreg_p (src))
+ && ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
+ && !REG_CAN_CHANGE_MODE_P (REGNO (dest),
+ GET_MODE (SUBREG_REG (src)),
+ GET_MODE (src)))
+ && (REG_P (dest)
+ || (GET_CODE (dest) == SUBREG
+ && REG_P (SUBREG_REG (dest)))))
+ {
+ SUBST (SET_DEST (x),
+ gen_lowpart (GET_MODE (SUBREG_REG (src)),
+ dest));
+ SUBST (SET_SRC (x), SUBREG_REG (src));
+
+ src = SET_SRC (x), dest = SET_DEST (x);
+ }
+
+ /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
+ would require a paradoxical subreg. Replace the subreg with a
+ zero_extend to avoid the reload that would otherwise be required.
+ Don't do this unless we have a scalar integer mode, otherwise the
+ transformation is incorrect. */
+
+ enum rtx_code extend_op;
+ if (paradoxical_subreg_p (src)
+ && MEM_P (SUBREG_REG (src))
+ && SCALAR_INT_MODE_P (GET_MODE (src))
+ && (extend_op = load_extend_op (GET_MODE (SUBREG_REG (src)))) != UNKNOWN)
+ {
+ SUBST (SET_SRC (x),
+ gen_rtx_fmt_e (extend_op, GET_MODE (src), SUBREG_REG (src)));
+
+ src = SET_SRC (x);
+ }
+
+ /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE, and we
+ are comparing an item known to be 0 or -1 against 0, use a logical
+ operation instead. Check for one of the arms being an IOR of the other
+ arm with some value. We compute three terms to be IOR'ed together. In
+ practice, at most two will be nonzero. Then we do the IOR's. */
+
+ if (GET_CODE (dest) != PC
+ && GET_CODE (src) == IF_THEN_ELSE
+ && is_int_mode (GET_MODE (src), &int_mode)
+ && (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE)
+ && XEXP (XEXP (src, 0), 1) == const0_rtx
+ && int_mode == GET_MODE (XEXP (XEXP (src, 0), 0))
+ && (!HAVE_conditional_move
+ || ! can_conditionally_move_p (int_mode))
+ && (num_sign_bit_copies (XEXP (XEXP (src, 0), 0), int_mode)
+ == GET_MODE_PRECISION (int_mode))
+ && ! side_effects_p (src))
+ {
+ rtx true_rtx = (GET_CODE (XEXP (src, 0)) == NE
+ ? XEXP (src, 1) : XEXP (src, 2));
+ rtx false_rtx = (GET_CODE (XEXP (src, 0)) == NE
+ ? XEXP (src, 2) : XEXP (src, 1));
+ rtx term1 = const0_rtx, term2, term3;
+
+ if (GET_CODE (true_rtx) == IOR
+ && rtx_equal_p (XEXP (true_rtx, 0), false_rtx))
+ term1 = false_rtx, true_rtx = XEXP (true_rtx, 1), false_rtx = const0_rtx;
+ else if (GET_CODE (true_rtx) == IOR
+ && rtx_equal_p (XEXP (true_rtx, 1), false_rtx))
+ term1 = false_rtx, true_rtx = XEXP (true_rtx, 0), false_rtx = const0_rtx;
+ else if (GET_CODE (false_rtx) == IOR
+ && rtx_equal_p (XEXP (false_rtx, 0), true_rtx))
+ term1 = true_rtx, false_rtx = XEXP (false_rtx, 1), true_rtx = const0_rtx;
+ else if (GET_CODE (false_rtx) == IOR
+ && rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
+ term1 = true_rtx, false_rtx = XEXP (false_rtx, 0), true_rtx = const0_rtx;
+
+ term2 = simplify_gen_binary (AND, int_mode,
+ XEXP (XEXP (src, 0), 0), true_rtx);
+ term3 = simplify_gen_binary (AND, int_mode,
+ simplify_gen_unary (NOT, int_mode,
+ XEXP (XEXP (src, 0), 0),
+ int_mode),
+ false_rtx);
+
+ SUBST (SET_SRC (x),
+ simplify_gen_binary (IOR, int_mode,
+ simplify_gen_binary (IOR, int_mode,
+ term1, term2),
+ term3));
+
+ src = SET_SRC (x);
+ }
+
+ /* If either SRC or DEST is a CLOBBER of (const_int 0), make this
+ whole thing fail. */
+ if (GET_CODE (src) == CLOBBER && XEXP (src, 0) == const0_rtx)
+ return src;
+ else if (GET_CODE (dest) == CLOBBER && XEXP (dest, 0) == const0_rtx)
+ return dest;
+ else
+ /* Convert this into a field assignment operation, if possible. */
+ return make_field_assignment (x);
+}
+
+/* Simplify, X, and AND, IOR, or XOR operation, and return the simplified
+ result. */
+
+static rtx
+simplify_logical (rtx x)
+{
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+ scalar_int_mode mode;
+
+ switch (GET_CODE (x))
+ {
+ case AND:
+ /* We can call simplify_and_const_int only if we don't lose
+ any (sign) bits when converting INTVAL (op1) to
+ "unsigned HOST_WIDE_INT". */
+ if (is_a <scalar_int_mode> (GET_MODE (x), &mode)
+ && CONST_INT_P (op1)
+ && (HWI_COMPUTABLE_MODE_P (mode)
+ || INTVAL (op1) > 0))
+ {
+ x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
+ if (GET_CODE (x) != AND)
+ return x;
+
+ op0 = XEXP (x, 0);
+ op1 = XEXP (x, 1);
+ }
+
+ /* If we have any of (and (ior A B) C) or (and (xor A B) C),
+ apply the distributive law and then the inverse distributive
+ law to see if things simplify. */
+ if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
+ {
+ rtx result = distribute_and_simplify_rtx (x, 0);
+ if (result)
+ return result;
+ }
+ if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
+ {
+ rtx result = distribute_and_simplify_rtx (x, 1);
+ if (result)
+ return result;
+ }
+ break;
+
+ case IOR:
+ /* If we have (ior (and A B) C), apply the distributive law and then
+ the inverse distributive law to see if things simplify. */
+
+ if (GET_CODE (op0) == AND)
+ {
+ rtx result = distribute_and_simplify_rtx (x, 0);
+ if (result)
+ return result;
+ }
+
+ if (GET_CODE (op1) == AND)
+ {
+ rtx result = distribute_and_simplify_rtx (x, 1);
+ if (result)
+ return result;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return x;
+}
+
+/* We consider ZERO_EXTRACT, SIGN_EXTRACT, and SIGN_EXTEND as "compound
+ operations" because they can be replaced with two more basic operations.
+ ZERO_EXTEND is also considered "compound" because it can be replaced with
+ an AND operation, which is simpler, though only one operation.
+
+ The function expand_compound_operation is called with an rtx expression
+ and will convert it to the appropriate shifts and AND operations,
+ simplifying at each stage.
+
+ The function make_compound_operation is called to convert an expression
+ consisting of shifts and ANDs into the equivalent compound expression.
+ It is the inverse of this function, loosely speaking. */
+
+static rtx
+expand_compound_operation (rtx x)
+{
+ unsigned HOST_WIDE_INT pos = 0, len;
+ int unsignedp = 0;
+ unsigned int modewidth;
+ rtx tem;
+ scalar_int_mode inner_mode;
+
+ switch (GET_CODE (x))
+ {
+ case ZERO_EXTEND:
+ unsignedp = 1;
+ /* FALLTHRU */
+ case SIGN_EXTEND:
+ /* We can't necessarily use a const_int for a multiword mode;
+ it depends on implicitly extending the value.
+ Since we don't know the right way to extend it,
+ we can't tell whether the implicit way is right.
+
+ Even for a mode that is no wider than a const_int,
+ we can't win, because we need to sign extend one of its bits through
+ the rest of it, and we don't know which bit. */
+ if (CONST_INT_P (XEXP (x, 0)))
+ return x;
+
+ /* Reject modes that aren't scalar integers because turning vector
+ or complex modes into shifts causes problems. */
+ if (!is_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)), &inner_mode))
+ return x;
+
+ /* Return if (subreg:MODE FROM 0) is not a safe replacement for
+ (zero_extend:MODE FROM) or (sign_extend:MODE FROM). It is for any MEM
+ because (SUBREG (MEM...)) is guaranteed to cause the MEM to be
+ reloaded. If not for that, MEM's would very rarely be safe.
+
+ Reject modes bigger than a word, because we might not be able
+ to reference a two-register group starting with an arbitrary register
+ (and currently gen_lowpart might crash for a SUBREG). */
+
+ if (GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+ return x;
+
+ len = GET_MODE_PRECISION (inner_mode);
+ /* If the inner object has VOIDmode (the only way this can happen
+ is if it is an ASM_OPERANDS), we can't do anything since we don't
+ know how much masking to do. */
+ if (len == 0)
+ return x;
+
+ break;
+
+ case ZERO_EXTRACT:
+ unsignedp = 1;
+
+ /* fall through */
+
+ case SIGN_EXTRACT:
+ /* If the operand is a CLOBBER, just return it. */
+ if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+ return XEXP (x, 0);
+
+ if (!CONST_INT_P (XEXP (x, 1))
+ || !CONST_INT_P (XEXP (x, 2)))
+ return x;
+
+ /* Reject modes that aren't scalar integers because turning vector
+ or complex modes into shifts causes problems. */
+ if (!is_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)), &inner_mode))
+ return x;
+
+ len = INTVAL (XEXP (x, 1));
+ pos = INTVAL (XEXP (x, 2));
+
+ /* This should stay within the object being extracted, fail otherwise. */
+ if (len + pos > GET_MODE_PRECISION (inner_mode))
+ return x;
+
+ if (BITS_BIG_ENDIAN)
+ pos = GET_MODE_PRECISION (inner_mode) - len - pos;
+
+ break;
+
+ default:
+ return x;
+ }
+
+ /* We've rejected non-scalar operations by now. */
+ scalar_int_mode mode = as_a <scalar_int_mode> (GET_MODE (x));
+
+ /* Convert sign extension to zero extension, if we know that the high
+ bit is not set, as this is easier to optimize. It will be converted
+ back to cheaper alternative in make_extraction. */
+ if (GET_CODE (x) == SIGN_EXTEND
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && ((nonzero_bits (XEXP (x, 0), inner_mode)
+ & ~(((unsigned HOST_WIDE_INT) GET_MODE_MASK (inner_mode)) >> 1))
+ == 0))
+ {
+ rtx temp = gen_rtx_ZERO_EXTEND (mode, XEXP (x, 0));
+ rtx temp2 = expand_compound_operation (temp);
+
+ /* Make sure this is a profitable operation. */
+ if (set_src_cost (x, mode, optimize_this_for_speed_p)
+ > set_src_cost (temp2, mode, optimize_this_for_speed_p))
+ return temp2;
+ else if (set_src_cost (x, mode, optimize_this_for_speed_p)
+ > set_src_cost (temp, mode, optimize_this_for_speed_p))
+ return temp;
+ else
+ return x;
+ }
+
+ /* We can optimize some special cases of ZERO_EXTEND. */
+ if (GET_CODE (x) == ZERO_EXTEND)
+ {
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we
+ know that the last value didn't have any inappropriate bits
+ set. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && (nonzero_bits (XEXP (XEXP (x, 0), 0), mode)
+ & ~GET_MODE_MASK (inner_mode)) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == mode
+ && subreg_lowpart_p (XEXP (x, 0))
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), mode)
+ & ~GET_MODE_MASK (inner_mode)) == 0)
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
+ is a comparison and STORE_FLAG_VALUE permits. This is like
+ the first case, but it works even when MODE is larger
+ than HOST_WIDE_INT. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode
+ && COMPARISON_P (XEXP (XEXP (x, 0), 0))
+ && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
+ && (STORE_FLAG_VALUE & ~GET_MODE_MASK (inner_mode)) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == mode
+ && subreg_lowpart_p (XEXP (x, 0))
+ && COMPARISON_P (SUBREG_REG (XEXP (x, 0)))
+ && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
+ && (STORE_FLAG_VALUE & ~GET_MODE_MASK (inner_mode)) == 0)
+ return SUBREG_REG (XEXP (x, 0));
+
+ }
+
+ /* If we reach here, we want to return a pair of shifts. The inner
+ shift is a left shift of BITSIZE - POS - LEN bits. The outer
+ shift is a right shift of BITSIZE - LEN bits. It is arithmetic or
+ logical depending on the value of UNSIGNEDP.
+
+ If this was a ZERO_EXTEND or ZERO_EXTRACT, this pair of shifts will be
+ converted into an AND of a shift.
+
+ We must check for the case where the left shift would have a negative
+ count. This can happen in a case like (x >> 31) & 255 on machines
+ that can't shift by a constant. On those machines, we would first
+ combine the shift with the AND to produce a variable-position
+ extraction. Then the constant of 31 would be substituted in
+ to produce such a position. */
+
+ modewidth = GET_MODE_PRECISION (mode);
+ if (modewidth >= pos + len)
+ {
+ tem = gen_lowpart (mode, XEXP (x, 0));
+ if (!tem || GET_CODE (tem) == CLOBBER)
+ return x;
+ tem = simplify_shift_const (NULL_RTX, ASHIFT, mode,
+ tem, modewidth - pos - len);
+ tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
+ mode, tem, modewidth - len);
+ }
+ else if (unsignedp && len < HOST_BITS_PER_WIDE_INT)
+ {
+ tem = simplify_shift_const (NULL_RTX, LSHIFTRT, inner_mode,
+ XEXP (x, 0), pos);
+ tem = gen_lowpart (mode, tem);
+ if (!tem || GET_CODE (tem) == CLOBBER)
+ return x;
+ tem = simplify_and_const_int (NULL_RTX, mode, tem,
+ (HOST_WIDE_INT_1U << len) - 1);
+ }
+ else
+ /* Any other cases we can't handle. */
+ return x;
+
+ /* If we couldn't do this for some reason, return the original
+ expression. */
+ if (GET_CODE (tem) == CLOBBER)
+ return x;
+
+ return tem;
+}
+
+/* X is a SET which contains an assignment of one object into
+ a part of another (such as a bit-field assignment, STRICT_LOW_PART,
+ or certain SUBREGS). If possible, convert it into a series of
+ logical operations.
+
+ We half-heartedly support variable positions, but do not at all
+ support variable lengths. */
+
+static const_rtx
+expand_field_assignment (const_rtx x)
+{
+ rtx inner;
+ rtx pos; /* Always counts from low bit. */
+ int len, inner_len;
+ rtx mask, cleared, masked;
+ scalar_int_mode compute_mode;
+
+ /* Loop until we find something we can't simplify. */
+ while (1)
+ {
+ if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
+ && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
+ {
+ rtx x0 = XEXP (SET_DEST (x), 0);
+ if (!GET_MODE_PRECISION (GET_MODE (x0)).is_constant (&len))
+ break;
+ inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
+ pos = gen_int_mode (subreg_lsb (XEXP (SET_DEST (x), 0)),
+ MAX_MODE_INT);
+ }
+ else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
+ && CONST_INT_P (XEXP (SET_DEST (x), 1)))
+ {
+ inner = XEXP (SET_DEST (x), 0);
+ if (!GET_MODE_PRECISION (GET_MODE (inner)).is_constant (&inner_len))
+ break;
+
+ len = INTVAL (XEXP (SET_DEST (x), 1));
+ pos = XEXP (SET_DEST (x), 2);
+
+ /* A constant position should stay within the width of INNER. */
+ if (CONST_INT_P (pos) && INTVAL (pos) + len > inner_len)
+ break;
+
+ if (BITS_BIG_ENDIAN)
+ {
+ if (CONST_INT_P (pos))
+ pos = GEN_INT (inner_len - len - INTVAL (pos));
+ else if (GET_CODE (pos) == MINUS
+ && CONST_INT_P (XEXP (pos, 1))
+ && INTVAL (XEXP (pos, 1)) == inner_len - len)
+ /* If position is ADJUST - X, new position is X. */
+ pos = XEXP (pos, 0);
+ else
+ pos = simplify_gen_binary (MINUS, GET_MODE (pos),
+ gen_int_mode (inner_len - len,
+ GET_MODE (pos)),
+ pos);
+ }
+ }
+
+ /* If the destination is a subreg that overwrites the whole of the inner
+ register, we can move the subreg to the source. */
+ else if (GET_CODE (SET_DEST (x)) == SUBREG
+ /* We need SUBREGs to compute nonzero_bits properly. */
+ && nonzero_sign_valid
+ && !read_modify_subreg_p (SET_DEST (x)))
+ {
+ x = gen_rtx_SET (SUBREG_REG (SET_DEST (x)),
+ gen_lowpart
+ (GET_MODE (SUBREG_REG (SET_DEST (x))),
+ SET_SRC (x)));
+ continue;
+ }
+ else
+ break;
+
+ while (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
+ inner = SUBREG_REG (inner);
+
+ /* Don't attempt bitwise arithmetic on non scalar integer modes. */
+ if (!is_a <scalar_int_mode> (GET_MODE (inner), &compute_mode))
+ {
+ /* Don't do anything for vector or complex integral types. */
+ if (! FLOAT_MODE_P (GET_MODE (inner)))
+ break;
+
+ /* Try to find an integral mode to pun with. */
+ if (!int_mode_for_size (GET_MODE_BITSIZE (GET_MODE (inner)), 0)
+ .exists (&compute_mode))
+ break;
+
+ inner = gen_lowpart (compute_mode, inner);
+ }
+
+ /* Compute a mask of LEN bits, if we can do this on the host machine. */
+ if (len >= HOST_BITS_PER_WIDE_INT)
+ break;
+
+ /* Don't try to compute in too wide unsupported modes. */
+ if (!targetm.scalar_mode_supported_p (compute_mode))
+ break;
+
+ /* Now compute the equivalent expression. Make a copy of INNER
+ for the SET_DEST in case it is a MEM into which we will substitute;
+ we don't want shared RTL in that case. */
+ mask = gen_int_mode ((HOST_WIDE_INT_1U << len) - 1,
+ compute_mode);
+ cleared = simplify_gen_binary (AND, compute_mode,
+ simplify_gen_unary (NOT, compute_mode,
+ simplify_gen_binary (ASHIFT,
+ compute_mode,
+ mask, pos),
+ compute_mode),
+ inner);
+ masked = simplify_gen_binary (ASHIFT, compute_mode,
+ simplify_gen_binary (
+ AND, compute_mode,
+ gen_lowpart (compute_mode, SET_SRC (x)),
+ mask),
+ pos);
+
+ x = gen_rtx_SET (copy_rtx (inner),
+ simplify_gen_binary (IOR, compute_mode,
+ cleared, masked));
+ }
+
+ return x;
+}
+
+/* Return an RTX for a reference to LEN bits of INNER. If POS_RTX is nonzero,
+ it is an RTX that represents the (variable) starting position; otherwise,
+ POS is the (constant) starting bit position. Both are counted from the LSB.
+
+ UNSIGNEDP is nonzero for an unsigned reference and zero for a signed one.
+
+ IN_DEST is nonzero if this is a reference in the destination of a SET.
+ This is used when a ZERO_ or SIGN_EXTRACT isn't needed. If nonzero,
+ a STRICT_LOW_PART will be used, if zero, ZERO_EXTEND or SIGN_EXTEND will
+ be used.
+
+ IN_COMPARE is nonzero if we are in a COMPARE. This means that a
+ ZERO_EXTRACT should be built even for bits starting at bit 0.
+
+ MODE is the desired mode of the result (if IN_DEST == 0).
+
+ The result is an RTX for the extraction or NULL_RTX if the target
+ can't handle it. */
+
+static rtx
+make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
+ rtx pos_rtx, unsigned HOST_WIDE_INT len, int unsignedp,
+ int in_dest, int in_compare)
+{
+ /* This mode describes the size of the storage area
+ to fetch the overall value from. Within that, we
+ ignore the POS lowest bits, etc. */
+ machine_mode is_mode = GET_MODE (inner);
+ machine_mode inner_mode;
+ scalar_int_mode wanted_inner_mode;
+ scalar_int_mode wanted_inner_reg_mode = word_mode;
+ scalar_int_mode pos_mode = word_mode;
+ machine_mode extraction_mode = word_mode;
+ rtx new_rtx = 0;
+ rtx orig_pos_rtx = pos_rtx;
+ HOST_WIDE_INT orig_pos;
+
+ if (pos_rtx && CONST_INT_P (pos_rtx))
+ pos = INTVAL (pos_rtx), pos_rtx = 0;
+
+ if (GET_CODE (inner) == SUBREG
+ && subreg_lowpart_p (inner)
+ && (paradoxical_subreg_p (inner)
+ /* If trying or potentionally trying to extract
+ bits outside of is_mode, don't look through
+ non-paradoxical SUBREGs. See PR82192. */
+ || (pos_rtx == NULL_RTX
+ && known_le (pos + len, GET_MODE_PRECISION (is_mode)))))
+ {
+ /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
+ consider just the QI as the memory to extract from.
+ The subreg adds or removes high bits; its mode is
+ irrelevant to the meaning of this extraction,
+ since POS and LEN count from the lsb. */
+ if (MEM_P (SUBREG_REG (inner)))
+ is_mode = GET_MODE (SUBREG_REG (inner));
+ inner = SUBREG_REG (inner);
+ }
+ else if (GET_CODE (inner) == ASHIFT
+ && CONST_INT_P (XEXP (inner, 1))
+ && pos_rtx == 0 && pos == 0
+ && len > UINTVAL (XEXP (inner, 1)))
+ {
+ /* We're extracting the least significant bits of an rtx
+ (ashift X (const_int C)), where LEN > C. Extract the
+ least significant (LEN - C) bits of X, giving an rtx
+ whose mode is MODE, then shift it left C times. */
+ new_rtx = make_extraction (mode, XEXP (inner, 0),
+ 0, 0, len - INTVAL (XEXP (inner, 1)),
+ unsignedp, in_dest, in_compare);
+ if (new_rtx != 0)
+ return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1));
+ }
+ else if (GET_CODE (inner) == MULT
+ && CONST_INT_P (XEXP (inner, 1))
+ && pos_rtx == 0 && pos == 0)
+ {
+ /* We're extracting the least significant bits of an rtx
+ (mult X (const_int 2^C)), where LEN > C. Extract the
+ least significant (LEN - C) bits of X, giving an rtx
+ whose mode is MODE, then multiply it by 2^C. */
+ const HOST_WIDE_INT shift_amt = exact_log2 (INTVAL (XEXP (inner, 1)));
+ if (IN_RANGE (shift_amt, 1, len - 1))
+ {
+ new_rtx = make_extraction (mode, XEXP (inner, 0),
+ 0, 0, len - shift_amt,
+ unsignedp, in_dest, in_compare);
+ if (new_rtx)
+ return gen_rtx_MULT (mode, new_rtx, XEXP (inner, 1));
+ }
+ }
+ else if (GET_CODE (inner) == TRUNCATE
+ /* If trying or potentionally trying to extract
+ bits outside of is_mode, don't look through
+ TRUNCATE. See PR82192. */
+ && pos_rtx == NULL_RTX
+ && known_le (pos + len, GET_MODE_PRECISION (is_mode)))
+ inner = XEXP (inner, 0);
+
+ inner_mode = GET_MODE (inner);
+
+ /* See if this can be done without an extraction. We never can if the
+ width of the field is not the same as that of some integer mode. For
+ registers, we can only avoid the extraction if the position is at the
+ low-order bit and this is either not in the destination or we have the
+ appropriate STRICT_LOW_PART operation available.
+
+ For MEM, we can avoid an extract if the field starts on an appropriate
+ boundary and we can change the mode of the memory reference. */
+
+ scalar_int_mode tmode;
+ if (int_mode_for_size (len, 1).exists (&tmode)
+ && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
+ && !MEM_P (inner)
+ && (pos == 0 || REG_P (inner))
+ && (inner_mode == tmode
+ || !REG_P (inner)
+ || TRULY_NOOP_TRUNCATION_MODES_P (tmode, inner_mode)
+ || reg_truncated_to_mode (tmode, inner))
+ && (! in_dest
+ || (REG_P (inner)
+ && have_insn_for (STRICT_LOW_PART, tmode))))
+ || (MEM_P (inner) && pos_rtx == 0
+ && (pos
+ % (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode)
+ : BITS_PER_UNIT)) == 0
+ /* We can't do this if we are widening INNER_MODE (it
+ may not be aligned, for one thing). */
+ && !paradoxical_subreg_p (tmode, inner_mode)
+ && known_le (pos + len, GET_MODE_PRECISION (is_mode))
+ && (inner_mode == tmode
+ || (! mode_dependent_address_p (XEXP (inner, 0),
+ MEM_ADDR_SPACE (inner))
+ && ! MEM_VOLATILE_P (inner))))))
+ {
+ /* If INNER is a MEM, make a new MEM that encompasses just the desired
+ field. If the original and current mode are the same, we need not
+ adjust the offset. Otherwise, we do if bytes big endian.
+
+ If INNER is not a MEM, get a piece consisting of just the field
+ of interest (in this case POS % BITS_PER_WORD must be 0). */
+
+ if (MEM_P (inner))
+ {
+ poly_int64 offset;
+
+ /* POS counts from lsb, but make OFFSET count in memory order. */
+ if (BYTES_BIG_ENDIAN)
+ offset = bits_to_bytes_round_down (GET_MODE_PRECISION (is_mode)
+ - len - pos);
+ else
+ offset = pos / BITS_PER_UNIT;
+
+ new_rtx = adjust_address_nv (inner, tmode, offset);
+ }
+ else if (REG_P (inner))
+ {
+ if (tmode != inner_mode)
+ {
+ /* We can't call gen_lowpart in a DEST since we
+ always want a SUBREG (see below) and it would sometimes
+ return a new hard register. */
+ if (pos || in_dest)
+ {
+ poly_uint64 offset
+ = subreg_offset_from_lsb (tmode, inner_mode, pos);
+
+ /* Avoid creating invalid subregs, for example when
+ simplifying (x>>32)&255. */
+ if (!validate_subreg (tmode, inner_mode, inner, offset))
+ return NULL_RTX;
+
+ new_rtx = gen_rtx_SUBREG (tmode, inner, offset);
+ }
+ else
+ new_rtx = gen_lowpart (tmode, inner);
+ }
+ else
+ new_rtx = inner;
+ }
+ else
+ new_rtx = force_to_mode (inner, tmode,
+ len >= HOST_BITS_PER_WIDE_INT
+ ? HOST_WIDE_INT_M1U
+ : (HOST_WIDE_INT_1U << len) - 1, 0);
+
+ /* If this extraction is going into the destination of a SET,
+ make a STRICT_LOW_PART unless we made a MEM. */
+
+ if (in_dest)
+ return (MEM_P (new_rtx) ? new_rtx
+ : (GET_CODE (new_rtx) != SUBREG
+ ? gen_rtx_CLOBBER (tmode, const0_rtx)
+ : gen_rtx_STRICT_LOW_PART (VOIDmode, new_rtx)));
+
+ if (mode == tmode)
+ return new_rtx;
+
+ if (CONST_SCALAR_INT_P (new_rtx))
+ return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+ mode, new_rtx, tmode);
+
+ /* If we know that no extraneous bits are set, and that the high
+ bit is not set, convert the extraction to the cheaper of
+ sign and zero extension, that are equivalent in these cases. */
+ if (flag_expensive_optimizations
+ && (HWI_COMPUTABLE_MODE_P (tmode)
+ && ((nonzero_bits (new_rtx, tmode)
+ & ~(((unsigned HOST_WIDE_INT)GET_MODE_MASK (tmode)) >> 1))
+ == 0)))
+ {
+ rtx temp = gen_rtx_ZERO_EXTEND (mode, new_rtx);
+ rtx temp1 = gen_rtx_SIGN_EXTEND (mode, new_rtx);
+
+ /* Prefer ZERO_EXTENSION, since it gives more information to
+ backends. */
+ if (set_src_cost (temp, mode, optimize_this_for_speed_p)
+ <= set_src_cost (temp1, mode, optimize_this_for_speed_p))
+ return temp;
+ return temp1;
+ }
+
+ /* Otherwise, sign- or zero-extend unless we already are in the
+ proper mode. */
+
+ return (gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+ mode, new_rtx));
+ }
+
+ /* Unless this is a COMPARE or we have a funny memory reference,
+ don't do anything with zero-extending field extracts starting at
+ the low-order bit since they are simple AND operations. */
+ if (pos_rtx == 0 && pos == 0 && ! in_dest
+ && ! in_compare && unsignedp)
+ return 0;
+
+ /* Unless INNER is not MEM, reject this if we would be spanning bytes or
+ if the position is not a constant and the length is not 1. In all
+ other cases, we would only be going outside our object in cases when
+ an original shift would have been undefined. */
+ if (MEM_P (inner)
+ && ((pos_rtx == 0 && maybe_gt (pos + len, GET_MODE_PRECISION (is_mode)))
+ || (pos_rtx != 0 && len != 1)))
+ return 0;
+
+ enum extraction_pattern pattern = (in_dest ? EP_insv
+ : unsignedp ? EP_extzv : EP_extv);
+
+ /* If INNER is not from memory, we want it to have the mode of a register
+ extraction pattern's structure operand, or word_mode if there is no
+ such pattern. The same applies to extraction_mode and pos_mode
+ and their respective operands.
+
+ For memory, assume that the desired extraction_mode and pos_mode
+ are the same as for a register operation, since at present we don't
+ have named patterns for aligned memory structures. */
+ class extraction_insn insn;
+ unsigned int inner_size;
+ if (GET_MODE_BITSIZE (inner_mode).is_constant (&inner_size)
+ && get_best_reg_extraction_insn (&insn, pattern, inner_size, mode))
+ {
+ wanted_inner_reg_mode = insn.struct_mode.require ();
+ pos_mode = insn.pos_mode;
+ extraction_mode = insn.field_mode;
+ }
+
+ /* Never narrow an object, since that might not be safe. */
+
+ if (mode != VOIDmode
+ && partial_subreg_p (extraction_mode, mode))
+ extraction_mode = mode;
+
+ /* Punt if len is too large for extraction_mode. */
+ if (maybe_gt (len, GET_MODE_PRECISION (extraction_mode)))
+ return NULL_RTX;
+
+ if (!MEM_P (inner))
+ wanted_inner_mode = wanted_inner_reg_mode;
+ else
+ {
+ /* Be careful not to go beyond the extracted object and maintain the
+ natural alignment of the memory. */
+ wanted_inner_mode = smallest_int_mode_for_size (len);
+ while (pos % GET_MODE_BITSIZE (wanted_inner_mode) + len
+ > GET_MODE_BITSIZE (wanted_inner_mode))
+ wanted_inner_mode = GET_MODE_WIDER_MODE (wanted_inner_mode).require ();
+ }
+
+ orig_pos = pos;
+
+ if (BITS_BIG_ENDIAN)
+ {
+ /* POS is passed as if BITS_BIG_ENDIAN == 0, so we need to convert it to
+ BITS_BIG_ENDIAN style. If position is constant, compute new
+ position. Otherwise, build subtraction.
+ Note that POS is relative to the mode of the original argument.
+ If it's a MEM we need to recompute POS relative to that.
+ However, if we're extracting from (or inserting into) a register,
+ we want to recompute POS relative to wanted_inner_mode. */
+ int width;
+ if (!MEM_P (inner))
+ width = GET_MODE_BITSIZE (wanted_inner_mode);
+ else if (!GET_MODE_BITSIZE (is_mode).is_constant (&width))
+ return NULL_RTX;
+
+ if (pos_rtx == 0)
+ pos = width - len - pos;
+ else
+ pos_rtx
+ = gen_rtx_MINUS (GET_MODE (pos_rtx),
+ gen_int_mode (width - len, GET_MODE (pos_rtx)),
+ pos_rtx);
+ /* POS may be less than 0 now, but we check for that below.
+ Note that it can only be less than 0 if !MEM_P (inner). */
+ }
+
+ /* If INNER has a wider mode, and this is a constant extraction, try to
+ make it smaller and adjust the byte to point to the byte containing
+ the value. */
+ if (wanted_inner_mode != VOIDmode
+ && inner_mode != wanted_inner_mode
+ && ! pos_rtx
+ && partial_subreg_p (wanted_inner_mode, is_mode)
+ && MEM_P (inner)
+ && ! mode_dependent_address_p (XEXP (inner, 0), MEM_ADDR_SPACE (inner))
+ && ! MEM_VOLATILE_P (inner))
+ {
+ poly_int64 offset = 0;
+
+ /* The computations below will be correct if the machine is big
+ endian in both bits and bytes or little endian in bits and bytes.
+ If it is mixed, we must adjust. */
+
+ /* If bytes are big endian and we had a paradoxical SUBREG, we must
+ adjust OFFSET to compensate. */
+ if (BYTES_BIG_ENDIAN
+ && paradoxical_subreg_p (is_mode, inner_mode))
+ offset -= GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (inner_mode);
+
+ /* We can now move to the desired byte. */
+ offset += (pos / GET_MODE_BITSIZE (wanted_inner_mode))
+ * GET_MODE_SIZE (wanted_inner_mode);
+ pos %= GET_MODE_BITSIZE (wanted_inner_mode);
+
+ if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
+ && is_mode != wanted_inner_mode)
+ offset = (GET_MODE_SIZE (is_mode)
+ - GET_MODE_SIZE (wanted_inner_mode) - offset);
+
+ inner = adjust_address_nv (inner, wanted_inner_mode, offset);
+ }
+
+ /* If INNER is not memory, get it into the proper mode. If we are changing
+ its mode, POS must be a constant and smaller than the size of the new
+ mode. */
+ else if (!MEM_P (inner))
+ {
+ /* On the LHS, don't create paradoxical subregs implicitely truncating
+ the register unless TARGET_TRULY_NOOP_TRUNCATION. */
+ if (in_dest
+ && !TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (inner),
+ wanted_inner_mode))
+ return NULL_RTX;
+
+ if (GET_MODE (inner) != wanted_inner_mode
+ && (pos_rtx != 0
+ || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
+ return NULL_RTX;
+
+ if (orig_pos < 0)
+ return NULL_RTX;
+
+ inner = force_to_mode (inner, wanted_inner_mode,
+ pos_rtx
+ || len + orig_pos >= HOST_BITS_PER_WIDE_INT
+ ? HOST_WIDE_INT_M1U
+ : (((HOST_WIDE_INT_1U << len) - 1)
+ << orig_pos),
+ 0);
+ }
+
+ /* Adjust mode of POS_RTX, if needed. If we want a wider mode, we
+ have to zero extend. Otherwise, we can just use a SUBREG.
+
+ We dealt with constant rtxes earlier, so pos_rtx cannot
+ have VOIDmode at this point. */
+ if (pos_rtx != 0
+ && (GET_MODE_SIZE (pos_mode)
+ > GET_MODE_SIZE (as_a <scalar_int_mode> (GET_MODE (pos_rtx)))))
+ {
+ rtx temp = simplify_gen_unary (ZERO_EXTEND, pos_mode, pos_rtx,
+ GET_MODE (pos_rtx));
+
+ /* If we know that no extraneous bits are set, and that the high
+ bit is not set, convert extraction to cheaper one - either
+ SIGN_EXTENSION or ZERO_EXTENSION, that are equivalent in these
+ cases. */
+ if (flag_expensive_optimizations
+ && (HWI_COMPUTABLE_MODE_P (GET_MODE (pos_rtx))
+ && ((nonzero_bits (pos_rtx, GET_MODE (pos_rtx))
+ & ~(((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (GET_MODE (pos_rtx)))
+ >> 1))
+ == 0)))
+ {
+ rtx temp1 = simplify_gen_unary (SIGN_EXTEND, pos_mode, pos_rtx,
+ GET_MODE (pos_rtx));
+
+ /* Prefer ZERO_EXTENSION, since it gives more information to
+ backends. */
+ if (set_src_cost (temp1, pos_mode, optimize_this_for_speed_p)
+ < set_src_cost (temp, pos_mode, optimize_this_for_speed_p))
+ temp = temp1;
+ }
+ pos_rtx = temp;
+ }
+
+ /* Make POS_RTX unless we already have it and it is correct. If we don't
+ have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
+ be a CONST_INT. */
+ if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
+ pos_rtx = orig_pos_rtx;
+
+ else if (pos_rtx == 0)
+ pos_rtx = GEN_INT (pos);
+
+ /* Make the required operation. See if we can use existing rtx. */
+ new_rtx = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
+ extraction_mode, inner, GEN_INT (len), pos_rtx);
+ if (! in_dest)
+ new_rtx = gen_lowpart (mode, new_rtx);
+
+ return new_rtx;
+}
+
+/* See if X (of mode MODE) contains an ASHIFT of COUNT or more bits that
+ can be commuted with any other operations in X. Return X without
+ that shift if so. */
+
+static rtx
+extract_left_shift (scalar_int_mode mode, rtx x, int count)
+{
+ enum rtx_code code = GET_CODE (x);
+ rtx tem;
+
+ switch (code)
+ {
+ case ASHIFT:
+ /* This is the shift itself. If it is wide enough, we will return
+ either the value being shifted if the shift count is equal to
+ COUNT or a shift for the difference. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= count)
+ return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0),
+ INTVAL (XEXP (x, 1)) - count);
+ break;
+
+ case NEG: case NOT:
+ if ((tem = extract_left_shift (mode, XEXP (x, 0), count)) != 0)
+ return simplify_gen_unary (code, mode, tem, mode);
+
+ break;
+
+ case PLUS: case IOR: case XOR: case AND:
+ /* If we can safely shift this constant and we find the inner shift,
+ make a new operation. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && (UINTVAL (XEXP (x, 1))
+ & (((HOST_WIDE_INT_1U << count)) - 1)) == 0
+ && (tem = extract_left_shift (mode, XEXP (x, 0), count)) != 0)
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1)) >> count;
+ return simplify_gen_binary (code, mode, tem,
+ gen_int_mode (val, mode));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Subroutine of make_compound_operation. *X_PTR is the rtx at the current
+ level of the expression and MODE is its mode. IN_CODE is as for
+ make_compound_operation. *NEXT_CODE_PTR is the value of IN_CODE
+ that should be used when recursing on operands of *X_PTR.
+
+ There are two possible actions:
+
+ - Return null. This tells the caller to recurse on *X_PTR with IN_CODE
+ equal to *NEXT_CODE_PTR, after which *X_PTR holds the final value.
+
+ - Return a new rtx, which the caller returns directly. */
+
+static rtx
+make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
+ enum rtx_code in_code,
+ enum rtx_code *next_code_ptr)
+{
+ rtx x = *x_ptr;
+ enum rtx_code next_code = *next_code_ptr;
+ enum rtx_code code = GET_CODE (x);
+ int mode_width = GET_MODE_PRECISION (mode);
+ rtx rhs, lhs;
+ rtx new_rtx = 0;
+ int i;
+ rtx tem;
+ scalar_int_mode inner_mode;
+ bool equality_comparison = false;
+
+ if (in_code == EQ)
+ {
+ equality_comparison = true;
+ in_code = COMPARE;
+ }
+
+ /* Process depending on the code of this operation. If NEW is set
+ nonzero, it will be returned. */
+
+ switch (code)
+ {
+ case ASHIFT:
+ /* Convert shifts by constants into multiplications if inside
+ an address. */
+ if (in_code == MEM && CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
+ && INTVAL (XEXP (x, 1)) >= 0)
+ {
+ HOST_WIDE_INT count = INTVAL (XEXP (x, 1));
+ HOST_WIDE_INT multval = HOST_WIDE_INT_1 << count;
+
+ new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+ if (GET_CODE (new_rtx) == NEG)
+ {
+ new_rtx = XEXP (new_rtx, 0);
+ multval = -multval;
+ }
+ multval = trunc_int_for_mode (multval, mode);
+ new_rtx = gen_rtx_MULT (mode, new_rtx, gen_int_mode (multval, mode));
+ }
+ break;
+
+ case PLUS:
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
+ lhs = make_compound_operation (lhs, next_code);
+ rhs = make_compound_operation (rhs, next_code);
+ if (GET_CODE (lhs) == MULT && GET_CODE (XEXP (lhs, 0)) == NEG)
+ {
+ tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (lhs, 0), 0),
+ XEXP (lhs, 1));
+ new_rtx = simplify_gen_binary (MINUS, mode, rhs, tem);
+ }
+ else if (GET_CODE (lhs) == MULT
+ && (CONST_INT_P (XEXP (lhs, 1)) && INTVAL (XEXP (lhs, 1)) < 0))
+ {
+ tem = simplify_gen_binary (MULT, mode, XEXP (lhs, 0),
+ simplify_gen_unary (NEG, mode,
+ XEXP (lhs, 1),
+ mode));
+ new_rtx = simplify_gen_binary (MINUS, mode, rhs, tem);
+ }
+ else
+ {
+ SUBST (XEXP (x, 0), lhs);
+ SUBST (XEXP (x, 1), rhs);
+ }
+ maybe_swap_commutative_operands (x);
+ return x;
+
+ case MINUS:
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
+ lhs = make_compound_operation (lhs, next_code);
+ rhs = make_compound_operation (rhs, next_code);
+ if (GET_CODE (rhs) == MULT && GET_CODE (XEXP (rhs, 0)) == NEG)
+ {
+ tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (rhs, 0), 0),
+ XEXP (rhs, 1));
+ return simplify_gen_binary (PLUS, mode, tem, lhs);
+ }
+ else if (GET_CODE (rhs) == MULT
+ && (CONST_INT_P (XEXP (rhs, 1)) && INTVAL (XEXP (rhs, 1)) < 0))
+ {
+ tem = simplify_gen_binary (MULT, mode, XEXP (rhs, 0),
+ simplify_gen_unary (NEG, mode,
+ XEXP (rhs, 1),
+ mode));
+ return simplify_gen_binary (PLUS, mode, tem, lhs);
+ }
+ else
+ {
+ SUBST (XEXP (x, 0), lhs);
+ SUBST (XEXP (x, 1), rhs);
+ return x;
+ }
+
+ case AND:
+ /* If the second operand is not a constant, we can't do anything
+ with it. */
+ if (!CONST_INT_P (XEXP (x, 1)))
+ break;
+
+ /* If the constant is a power of two minus one and the first operand
+ is a logical right shift, make an extraction. */
+ if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
+ {
+ new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1),
+ i, 1, 0, in_code == COMPARE);
+ }
+
+ /* Same as previous, but for (subreg (lshiftrt ...)) in first op. */
+ else if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (x, 0))
+ && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (XEXP (x, 0))),
+ &inner_mode)
+ && GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
+ {
+ rtx inner_x0 = SUBREG_REG (XEXP (x, 0));
+ new_rtx = make_compound_operation (XEXP (inner_x0, 0), next_code);
+ new_rtx = make_extraction (inner_mode, new_rtx, 0,
+ XEXP (inner_x0, 1),
+ i, 1, 0, in_code == COMPARE);
+
+ /* If we narrowed the mode when dropping the subreg, then we lose. */
+ if (GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (mode))
+ new_rtx = NULL;
+
+ /* If that didn't give anything, see if the AND simplifies on
+ its own. */
+ if (!new_rtx && i >= 0)
+ {
+ new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx, 0, NULL_RTX, i, 1,
+ 0, in_code == COMPARE);
+ }
+ }
+ /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)). */
+ else if ((GET_CODE (XEXP (x, 0)) == XOR
+ || GET_CODE (XEXP (x, 0)) == IOR)
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == LSHIFTRT
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
+ {
+ /* Apply the distributive law, and then try to make extractions. */
+ new_rtx = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
+ gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
+ XEXP (x, 1)),
+ gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
+ XEXP (x, 1)));
+ new_rtx = make_compound_operation (new_rtx, in_code);
+ }
+
+ /* If we are have (and (rotate X C) M) and C is larger than the number
+ of bits in M, this is an extraction. */
+
+ else if (GET_CODE (XEXP (x, 0)) == ROTATE
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0
+ && i <= INTVAL (XEXP (XEXP (x, 0), 1)))
+ {
+ new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx,
+ (GET_MODE_PRECISION (mode)
+ - INTVAL (XEXP (XEXP (x, 0), 1))),
+ NULL_RTX, i, 1, 0, in_code == COMPARE);
+ }
+
+ /* On machines without logical shifts, if the operand of the AND is
+ a logical shift and our mask turns off all the propagated sign
+ bits, we can replace the logical shift with an arithmetic shift. */
+ else if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ && !have_insn_for (LSHIFTRT, mode)
+ && have_insn_for (ASHIFTRT, mode)
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
+ && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
+ && mode_width <= HOST_BITS_PER_WIDE_INT)
+ {
+ unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+
+ mask >>= INTVAL (XEXP (XEXP (x, 0), 1));
+ if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
+ SUBST (XEXP (x, 0),
+ gen_rtx_ASHIFTRT (mode,
+ make_compound_operation (XEXP (XEXP (x,
+ 0),
+ 0),
+ next_code),
+ XEXP (XEXP (x, 0), 1)));
+ }
+
+ /* If the constant is one less than a power of two, this might be
+ representable by an extraction even if no shift is present.
+ If it doesn't end up being a ZERO_EXTEND, we will ignore it unless
+ we are in a COMPARE. */
+ else if ((i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
+ new_rtx = make_extraction (mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ 0, NULL_RTX, i, 1, 0, in_code == COMPARE);
+
+ /* If we are in a comparison and this is an AND with a power of two,
+ convert this into the appropriate bit extract. */
+ else if (in_code == COMPARE
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
+ && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1))
+ new_rtx = make_extraction (mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ i, NULL_RTX, 1, 1, 0, 1);
+
+ /* If the one operand is a paradoxical subreg of a register or memory and
+ the constant (limited to the smaller mode) has only zero bits where
+ the sub expression has known zero bits, this can be expressed as
+ a zero_extend. */
+ else if (GET_CODE (XEXP (x, 0)) == SUBREG)
+ {
+ rtx sub;
+
+ sub = XEXP (XEXP (x, 0), 0);
+ machine_mode sub_mode = GET_MODE (sub);
+ int sub_width;
+ if ((REG_P (sub) || MEM_P (sub))
+ && GET_MODE_PRECISION (sub_mode).is_constant (&sub_width)
+ && sub_width < mode_width)
+ {
+ unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (sub_mode);
+ unsigned HOST_WIDE_INT mask;
+
+ /* original AND constant with all the known zero bits set */
+ mask = UINTVAL (XEXP (x, 1)) | (~nonzero_bits (sub, sub_mode));
+ if ((mask & mode_mask) == mode_mask)
+ {
+ new_rtx = make_compound_operation (sub, next_code);
+ new_rtx = make_extraction (mode, new_rtx, 0, 0, sub_width,
+ 1, 0, in_code == COMPARE);
+ }
+ }
+ }
+
+ break;
+
+ case LSHIFTRT:
+ /* If the sign bit is known to be zero, replace this with an
+ arithmetic shift. */
+ if (have_insn_for (ASHIFTRT, mode)
+ && ! have_insn_for (LSHIFTRT, mode)
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
+ {
+ new_rtx = gen_rtx_ASHIFTRT (mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ XEXP (x, 1));
+ break;
+ }
+
+ /* fall through */
+
+ case ASHIFTRT:
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
+
+ /* If we have (ashiftrt (ashift foo C1) C2) with C2 >= C1,
+ this is a SIGN_EXTRACT. */
+ if (CONST_INT_P (rhs)
+ && GET_CODE (lhs) == ASHIFT
+ && CONST_INT_P (XEXP (lhs, 1))
+ && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))
+ && INTVAL (XEXP (lhs, 1)) >= 0
+ && INTVAL (rhs) < mode_width)
+ {
+ new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
+ new_rtx = make_extraction (mode, new_rtx,
+ INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
+ NULL_RTX, mode_width - INTVAL (rhs),
+ code == LSHIFTRT, 0, in_code == COMPARE);
+ break;
+ }
+
+ /* See if we have operations between an ASHIFTRT and an ASHIFT.
+ If so, try to merge the shifts into a SIGN_EXTEND. We could
+ also do this for some cases of SIGN_EXTRACT, but it doesn't
+ seem worth the effort; the case checked for occurs on Alpha. */
+
+ if (!OBJECT_P (lhs)
+ && ! (GET_CODE (lhs) == SUBREG
+ && (OBJECT_P (SUBREG_REG (lhs))))
+ && CONST_INT_P (rhs)
+ && INTVAL (rhs) >= 0
+ && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
+ && INTVAL (rhs) < mode_width
+ && (new_rtx = extract_left_shift (mode, lhs, INTVAL (rhs))) != 0)
+ new_rtx = make_extraction (mode, make_compound_operation (new_rtx,
+ next_code),
+ 0, NULL_RTX, mode_width - INTVAL (rhs),
+ code == LSHIFTRT, 0, in_code == COMPARE);
+
+ break;
+
+ case SUBREG:
+ /* Call ourselves recursively on the inner expression. If we are
+ narrowing the object and it has a different RTL code from
+ what it originally did, do this SUBREG as a force_to_mode. */
+ {
+ rtx inner = SUBREG_REG (x), simplified;
+ enum rtx_code subreg_code = in_code;
+
+ /* If the SUBREG is masking of a logical right shift,
+ make an extraction. */
+ if (GET_CODE (inner) == LSHIFTRT
+ && is_a <scalar_int_mode> (GET_MODE (inner), &inner_mode)
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (inner_mode)
+ && CONST_INT_P (XEXP (inner, 1))
+ && UINTVAL (XEXP (inner, 1)) < GET_MODE_PRECISION (inner_mode)
+ && subreg_lowpart_p (x))
+ {
+ new_rtx = make_compound_operation (XEXP (inner, 0), next_code);
+ int width = GET_MODE_PRECISION (inner_mode)
+ - INTVAL (XEXP (inner, 1));
+ if (width > mode_width)
+ width = mode_width;
+ new_rtx = make_extraction (mode, new_rtx, 0, XEXP (inner, 1),
+ width, 1, 0, in_code == COMPARE);
+ break;
+ }
+
+ /* If in_code is COMPARE, it isn't always safe to pass it through
+ to the recursive make_compound_operation call. */
+ if (subreg_code == COMPARE
+ && (!subreg_lowpart_p (x)
+ || GET_CODE (inner) == SUBREG
+ /* (subreg:SI (and:DI (reg:DI) (const_int 0x800000000)) 0)
+ is (const_int 0), rather than
+ (subreg:SI (lshiftrt:DI (reg:DI) (const_int 35)) 0).
+ Similarly (subreg:QI (and:SI (reg:SI) (const_int 0x80)) 0)
+ for non-equality comparisons against 0 is not equivalent
+ to (subreg:QI (lshiftrt:SI (reg:SI) (const_int 7)) 0). */
+ || (GET_CODE (inner) == AND
+ && CONST_INT_P (XEXP (inner, 1))
+ && partial_subreg_p (x)
+ && exact_log2 (UINTVAL (XEXP (inner, 1)))
+ >= GET_MODE_BITSIZE (mode) - 1)))
+ subreg_code = SET;
+
+ tem = make_compound_operation (inner, subreg_code);
+
+ simplified
+ = simplify_subreg (mode, tem, GET_MODE (inner), SUBREG_BYTE (x));
+ if (simplified)
+ tem = simplified;
+
+ if (GET_CODE (tem) != GET_CODE (inner)
+ && partial_subreg_p (x)
+ && subreg_lowpart_p (x))
+ {
+ rtx newer
+ = force_to_mode (tem, mode, HOST_WIDE_INT_M1U, 0);
+
+ /* If we have something other than a SUBREG, we might have
+ done an expansion, so rerun ourselves. */
+ if (GET_CODE (newer) != SUBREG)
+ newer = make_compound_operation (newer, in_code);
+
+ /* force_to_mode can expand compounds. If it just re-expanded
+ the compound, use gen_lowpart to convert to the desired
+ mode. */
+ if (rtx_equal_p (newer, x)
+ /* Likewise if it re-expanded the compound only partially.
+ This happens for SUBREG of ZERO_EXTRACT if they extract
+ the same number of bits. */
+ || (GET_CODE (newer) == SUBREG
+ && (GET_CODE (SUBREG_REG (newer)) == LSHIFTRT
+ || GET_CODE (SUBREG_REG (newer)) == ASHIFTRT)
+ && GET_CODE (inner) == AND
+ && rtx_equal_p (SUBREG_REG (newer), XEXP (inner, 0))))
+ return gen_lowpart (GET_MODE (x), tem);
+
+ return newer;
+ }
+
+ if (simplified)
+ return tem;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (new_rtx)
+ *x_ptr = gen_lowpart (mode, new_rtx);
+ *next_code_ptr = next_code;
+ return NULL_RTX;
+}
+
+/* Look at the expression rooted at X. Look for expressions
+ equivalent to ZERO_EXTRACT, SIGN_EXTRACT, ZERO_EXTEND, SIGN_EXTEND.
+ Form these expressions.
+
+ Return the new rtx, usually just X.
+
+ Also, for machines like the VAX that don't have logical shift insns,
+ try to convert logical to arithmetic shift operations in cases where
+ they are equivalent. This undoes the canonicalizations to logical
+ shifts done elsewhere.
+
+ We try, as much as possible, to re-use rtl expressions to save memory.
+
+ IN_CODE says what kind of expression we are processing. Normally, it is
+ SET. In a memory address it is MEM. When processing the arguments of
+ a comparison or a COMPARE against zero, it is COMPARE, or EQ if more
+ precisely it is an equality comparison against zero. */
+
+rtx
+make_compound_operation (rtx x, enum rtx_code in_code)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt;
+ int i, j;
+ enum rtx_code next_code;
+ rtx new_rtx, tem;
+
+ /* Select the code to be used in recursive calls. Once we are inside an
+ address, we stay there. If we have a comparison, set to COMPARE,
+ but once inside, go back to our default of SET. */
+
+ next_code = (code == MEM ? MEM
+ : ((code == COMPARE || COMPARISON_P (x))
+ && XEXP (x, 1) == const0_rtx) ? COMPARE
+ : in_code == COMPARE || in_code == EQ ? SET : in_code);
+
+ scalar_int_mode mode;
+ if (is_a <scalar_int_mode> (GET_MODE (x), &mode))
+ {
+ rtx new_rtx = make_compound_operation_int (mode, &x, in_code,
+ &next_code);
+ if (new_rtx)
+ return new_rtx;
+ code = GET_CODE (x);
+ }
+
+ /* Now recursively process each operand of this operation. We need to
+ handle ZERO_EXTEND specially so that we don't lose track of the
+ inner mode. */
+ if (code == ZERO_EXTEND)
+ {
+ new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+ tem = simplify_const_unary_operation (ZERO_EXTEND, GET_MODE (x),
+ new_rtx, GET_MODE (XEXP (x, 0)));
+ if (tem)
+ return tem;
+ SUBST (XEXP (x, 0), new_rtx);
+ return x;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ if (fmt[i] == 'e')
+ {
+ new_rtx = make_compound_operation (XEXP (x, i), next_code);
+ SUBST (XEXP (x, i), new_rtx);
+ }
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ new_rtx = make_compound_operation (XVECEXP (x, i, j), next_code);
+ SUBST (XVECEXP (x, i, j), new_rtx);
+ }
+
+ maybe_swap_commutative_operands (x);
+ return x;
+}
+
+/* Given M see if it is a value that would select a field of bits
+ within an item, but not the entire word. Return -1 if not.
+ Otherwise, return the starting position of the field, where 0 is the
+ low-order bit.
+
+ *PLEN is set to the length of the field. */
+
+static int
+get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
+{
+ /* Get the bit number of the first 1 bit from the right, -1 if none. */
+ int pos = m ? ctz_hwi (m) : -1;
+ int len = 0;
+
+ if (pos >= 0)
+ /* Now shift off the low-order zero bits and see if we have a
+ power of two minus 1. */
+ len = exact_log2 ((m >> pos) + 1);
+
+ if (len <= 0)
+ pos = -1;
+
+ *plen = len;
+ return pos;
+}
+
+/* If X refers to a register that equals REG in value, replace these
+ references with REG. */
+static rtx
+canon_reg_for_combine (rtx x, rtx reg)
+{
+ rtx op0, op1, op2;
+ const char *fmt;
+ int i;
+ bool copied;
+
+ enum rtx_code code = GET_CODE (x);
+ switch (GET_RTX_CLASS (code))
+ {
+ case RTX_UNARY:
+ op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+ if (op0 != XEXP (x, 0))
+ return simplify_gen_unary (GET_CODE (x), GET_MODE (x), op0,
+ GET_MODE (reg));
+ break;
+
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+ op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+ if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+ return simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1);
+ break;
+
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+ op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+ if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+ return simplify_gen_relational (GET_CODE (x), GET_MODE (x),
+ GET_MODE (op0), op0, op1);
+ break;
+
+ case RTX_TERNARY:
+ case RTX_BITFIELD_OPS:
+ op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+ op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+ op2 = canon_reg_for_combine (XEXP (x, 2), reg);
+ if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1) || op2 != XEXP (x, 2))
+ return simplify_gen_ternary (GET_CODE (x), GET_MODE (x),
+ GET_MODE (op0), op0, op1, op2);
+ /* FALLTHRU */
+
+ case RTX_OBJ:
+ if (REG_P (x))
+ {
+ if (rtx_equal_p (get_last_value (reg), x)
+ || rtx_equal_p (reg, get_last_value (x)))
+ return reg;
+ else
+ break;
+ }
+
+ /* fall through */
+
+ default:
+ fmt = GET_RTX_FORMAT (code);
+ copied = false;
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ {
+ rtx op = canon_reg_for_combine (XEXP (x, i), reg);
+ if (op != XEXP (x, i))
+ {
+ if (!copied)
+ {
+ copied = true;
+ x = copy_rtx (x);
+ }
+ XEXP (x, i) = op;
+ }
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
+ if (op != XVECEXP (x, i, j))
+ {
+ if (!copied)
+ {
+ copied = true;
+ x = copy_rtx (x);
+ }
+ XVECEXP (x, i, j) = op;
+ }
+ }
+ }
+
+ break;
+ }
+
+ return x;
+}
+
+/* Return X converted to MODE. If the value is already truncated to
+ MODE we can just return a subreg even though in the general case we
+ would need an explicit truncation. */
+
+static rtx
+gen_lowpart_or_truncate (machine_mode mode, rtx x)
+{
+ if (!CONST_INT_P (x)
+ && partial_subreg_p (mode, GET_MODE (x))
+ && !TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x))
+ && !(REG_P (x) && reg_truncated_to_mode (mode, x)))
+ {
+ /* Bit-cast X into an integer mode. */
+ if (!SCALAR_INT_MODE_P (GET_MODE (x)))
+ x = gen_lowpart (int_mode_for_mode (GET_MODE (x)).require (), x);
+ x = simplify_gen_unary (TRUNCATE, int_mode_for_mode (mode).require (),
+ x, GET_MODE (x));
+ }
+
+ return gen_lowpart (mode, x);
+}
+
+/* See if X can be simplified knowing that we will only refer to it in
+ MODE and will only refer to those bits that are nonzero in MASK.
+ If other bits are being computed or if masking operations are done
+ that select a superset of the bits in MASK, they can sometimes be
+ ignored.
+
+ Return a possibly simplified expression, but always convert X to
+ MODE. If X is a CONST_INT, AND the CONST_INT with MASK.
+
+ If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
+ are all off in X. This is used when X will be complemented, by either
+ NOT, NEG, or XOR. */
+
+static rtx
+force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask,
+ int just_select)
+{
+ enum rtx_code code = GET_CODE (x);
+ int next_select = just_select || code == XOR || code == NOT || code == NEG;
+ machine_mode op_mode;
+ unsigned HOST_WIDE_INT nonzero;
+
+ /* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the
+ code below will do the wrong thing since the mode of such an
+ expression is VOIDmode.
+
+ Also do nothing if X is a CLOBBER; this can happen if X was
+ the return value from a call to gen_lowpart. */
+ if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
+ return x;
+
+ /* We want to perform the operation in its present mode unless we know
+ that the operation is valid in MODE, in which case we do the operation
+ in MODE. */
+ op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x))
+ && have_insn_for (code, mode))
+ ? mode : GET_MODE (x));
+
+ /* It is not valid to do a right-shift in a narrower mode
+ than the one it came in with. */
+ if ((code == LSHIFTRT || code == ASHIFTRT)
+ && partial_subreg_p (mode, GET_MODE (x)))
+ op_mode = GET_MODE (x);
+
+ /* Truncate MASK to fit OP_MODE. */
+ if (op_mode)
+ mask &= GET_MODE_MASK (op_mode);
+
+ /* Determine what bits of X are guaranteed to be (non)zero. */
+ nonzero = nonzero_bits (x, mode);
+
+ /* If none of the bits in X are needed, return a zero. */
+ if (!just_select && (nonzero & mask) == 0 && !side_effects_p (x))
+ x = const0_rtx;
+
+ /* If X is a CONST_INT, return a new one. Do this here since the
+ test below will fail. */
+ if (CONST_INT_P (x))
+ {
+ if (SCALAR_INT_MODE_P (mode))
+ return gen_int_mode (INTVAL (x) & mask, mode);
+ else
+ {
+ x = GEN_INT (INTVAL (x) & mask);
+ return gen_lowpart_common (mode, x);
+ }
+ }
+
+ /* If X is narrower than MODE and we want all the bits in X's mode, just
+ get X in the proper mode. */
+ if (paradoxical_subreg_p (mode, GET_MODE (x))
+ && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
+ return gen_lowpart (mode, x);
+
+ /* We can ignore the effect of a SUBREG if it narrows the mode or
+ if the constant masks to zero all the bits the mode doesn't have. */
+ if (GET_CODE (x) == SUBREG
+ && subreg_lowpart_p (x)
+ && (partial_subreg_p (x)
+ || (mask
+ & GET_MODE_MASK (GET_MODE (x))
+ & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))) == 0))
+ return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
+
+ scalar_int_mode int_mode, xmode;
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && is_a <scalar_int_mode> (GET_MODE (x), &xmode))
+ /* OP_MODE is either MODE or XMODE, so it must be a scalar
+ integer too. */
+ return force_int_to_mode (x, int_mode, xmode,
+ as_a <scalar_int_mode> (op_mode),
+ mask, just_select);
+
+ return gen_lowpart_or_truncate (mode, x);
+}
+
+/* Subroutine of force_to_mode that handles cases in which both X and
+ the result are scalar integers. MODE is the mode of the result,
+ XMODE is the mode of X, and OP_MODE says which of MODE or XMODE
+ is preferred for simplified versions of X. The other arguments
+ are as for force_to_mode. */
+
+static rtx
+force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
+ scalar_int_mode op_mode, unsigned HOST_WIDE_INT mask,
+ int just_select)
+{
+ enum rtx_code code = GET_CODE (x);
+ int next_select = just_select || code == XOR || code == NOT || code == NEG;
+ unsigned HOST_WIDE_INT fuller_mask;
+ rtx op0, op1, temp;
+ poly_int64 const_op0;
+
+ /* When we have an arithmetic operation, or a shift whose count we
+ do not know, we need to assume that all bits up to the highest-order
+ bit in MASK will be needed. This is how we form such a mask. */
+ if (mask & (HOST_WIDE_INT_1U << (HOST_BITS_PER_WIDE_INT - 1)))
+ fuller_mask = HOST_WIDE_INT_M1U;
+ else
+ fuller_mask = ((HOST_WIDE_INT_1U << (floor_log2 (mask) + 1))
+ - 1);
+
+ switch (code)
+ {
+ case CLOBBER:
+ /* If X is a (clobber (const_int)), return it since we know we are
+ generating something that won't match. */
+ return x;
+
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
+ x = expand_compound_operation (x);
+ if (GET_CODE (x) != code)
+ return force_to_mode (x, mode, mask, next_select);
+ break;
+
+ case TRUNCATE:
+ /* Similarly for a truncate. */
+ return force_to_mode (XEXP (x, 0), mode, mask, next_select);
+
+ case AND:
+ /* If this is an AND with a constant, convert it into an AND
+ whose constant is the AND of that constant with MASK. If it
+ remains an AND of MASK, delete it since it is redundant. */
+
+ if (CONST_INT_P (XEXP (x, 1)))
+ {
+ x = simplify_and_const_int (x, op_mode, XEXP (x, 0),
+ mask & INTVAL (XEXP (x, 1)));
+ xmode = op_mode;
+
+ /* If X is still an AND, see if it is an AND with a mask that
+ is just some low-order bits. If so, and it is MASK, we don't
+ need it. */
+
+ if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
+ && (INTVAL (XEXP (x, 1)) & GET_MODE_MASK (xmode)) == mask)
+ x = XEXP (x, 0);
+
+ /* If it remains an AND, try making another AND with the bits
+ in the mode mask that aren't in MASK turned on. If the
+ constant in the AND is wide enough, this might make a
+ cheaper constant. */
+
+ if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
+ && GET_MODE_MASK (xmode) != mask
+ && HWI_COMPUTABLE_MODE_P (xmode))
+ {
+ unsigned HOST_WIDE_INT cval
+ = UINTVAL (XEXP (x, 1)) | (GET_MODE_MASK (xmode) & ~mask);
+ rtx y;
+
+ y = simplify_gen_binary (AND, xmode, XEXP (x, 0),
+ gen_int_mode (cval, xmode));
+ if (set_src_cost (y, xmode, optimize_this_for_speed_p)
+ < set_src_cost (x, xmode, optimize_this_for_speed_p))
+ x = y;
+ }
+
+ break;
+ }
+
+ goto binop;
+
+ case PLUS:
+ /* In (and (plus FOO C1) M), if M is a mask that just turns off
+ low-order bits (as in an alignment operation) and FOO is already
+ aligned to that boundary, mask C1 to that boundary as well.
+ This may eliminate that PLUS and, later, the AND. */
+
+ {
+ unsigned int width = GET_MODE_PRECISION (mode);
+ unsigned HOST_WIDE_INT smask = mask;
+
+ /* If MODE is narrower than HOST_WIDE_INT and mask is a negative
+ number, sign extend it. */
+
+ if (width < HOST_BITS_PER_WIDE_INT
+ && (smask & (HOST_WIDE_INT_1U << (width - 1))) != 0)
+ smask |= HOST_WIDE_INT_M1U << width;
+
+ if (CONST_INT_P (XEXP (x, 1))
+ && pow2p_hwi (- smask)
+ && (nonzero_bits (XEXP (x, 0), mode) & ~smask) == 0
+ && (INTVAL (XEXP (x, 1)) & ~smask) != 0)
+ return force_to_mode (plus_constant (xmode, XEXP (x, 0),
+ (INTVAL (XEXP (x, 1)) & smask)),
+ mode, smask, next_select);
+ }
+
+ /* fall through */
+
+ case MULT:
+ /* Substituting into the operands of a widening MULT is not likely to
+ create RTL matching a machine insn. */
+ if (code == MULT
+ && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
+ && (GET_CODE (XEXP (x, 1)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
+ && REG_P (XEXP (XEXP (x, 0), 0))
+ && REG_P (XEXP (XEXP (x, 1), 0)))
+ return gen_lowpart_or_truncate (mode, x);
+
+ /* For PLUS, MINUS and MULT, we need any bits less significant than the
+ most significant bit in MASK since carries from those bits will
+ affect the bits we are interested in. */
+ mask = fuller_mask;
+ goto binop;
+
+ case MINUS:
+ /* If X is (minus C Y) where C's least set bit is larger than any bit
+ in the mask, then we may replace with (neg Y). */
+ if (poly_int_rtx_p (XEXP (x, 0), &const_op0)
+ && known_alignment (poly_uint64 (const_op0)) > mask)
+ {
+ x = simplify_gen_unary (NEG, xmode, XEXP (x, 1), xmode);
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ /* Similarly, if C contains every bit in the fuller_mask, then we may
+ replace with (not Y). */
+ if (CONST_INT_P (XEXP (x, 0))
+ && ((UINTVAL (XEXP (x, 0)) | fuller_mask) == UINTVAL (XEXP (x, 0))))
+ {
+ x = simplify_gen_unary (NOT, xmode, XEXP (x, 1), xmode);
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ mask = fuller_mask;
+ goto binop;
+
+ case IOR:
+ case XOR:
+ /* If X is (ior (lshiftrt FOO C1) C2), try to commute the IOR and
+ LSHIFTRT so we end up with an (and (lshiftrt (ior ...) ...) ...)
+ operation which may be a bitfield extraction. Ensure that the
+ constant we form is not wider than the mode of X. */
+
+ if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
+ && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
+ && CONST_INT_P (XEXP (x, 1))
+ && ((INTVAL (XEXP (XEXP (x, 0), 1))
+ + floor_log2 (INTVAL (XEXP (x, 1))))
+ < GET_MODE_PRECISION (xmode))
+ && (UINTVAL (XEXP (x, 1))
+ & ~nonzero_bits (XEXP (x, 0), xmode)) == 0)
+ {
+ temp = gen_int_mode ((INTVAL (XEXP (x, 1)) & mask)
+ << INTVAL (XEXP (XEXP (x, 0), 1)),
+ xmode);
+ temp = simplify_gen_binary (GET_CODE (x), xmode,
+ XEXP (XEXP (x, 0), 0), temp);
+ x = simplify_gen_binary (LSHIFTRT, xmode, temp,
+ XEXP (XEXP (x, 0), 1));
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ binop:
+ /* For most binary operations, just propagate into the operation and
+ change the mode if we have an operation of that mode. */
+
+ op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select);
+ op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select);
+
+ /* If we ended up truncating both operands, truncate the result of the
+ operation instead. */
+ if (GET_CODE (op0) == TRUNCATE
+ && GET_CODE (op1) == TRUNCATE)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = XEXP (op1, 0);
+ }
+
+ op0 = gen_lowpart_or_truncate (op_mode, op0);
+ op1 = gen_lowpart_or_truncate (op_mode, op1);
+
+ if (op_mode != xmode || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+ {
+ x = simplify_gen_binary (code, op_mode, op0, op1);
+ xmode = op_mode;
+ }
+ break;
+
+ case ASHIFT:
+ /* For left shifts, do the same, but just for the first operand.
+ However, we cannot do anything with shifts where we cannot
+ guarantee that the counts are smaller than the size of the mode
+ because such a count will have a different meaning in a
+ wider mode. */
+
+ if (! (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0
+ && INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (mode))
+ && ! (GET_MODE (XEXP (x, 1)) != VOIDmode
+ && (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
+ < (unsigned HOST_WIDE_INT) GET_MODE_PRECISION (mode))))
+ break;
+
+ /* If the shift count is a constant and we can do arithmetic in
+ the mode of the shift, refine which bits we need. Otherwise, use the
+ conservative form of the mask. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0
+ && INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (op_mode)
+ && HWI_COMPUTABLE_MODE_P (op_mode))
+ mask >>= INTVAL (XEXP (x, 1));
+ else
+ mask = fuller_mask;
+
+ op0 = gen_lowpart_or_truncate (op_mode,
+ force_to_mode (XEXP (x, 0), mode,
+ mask, next_select));
+
+ if (op_mode != xmode || op0 != XEXP (x, 0))
+ {
+ x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
+ xmode = op_mode;
+ }
+ break;
+
+ case LSHIFTRT:
+ /* Here we can only do something if the shift count is a constant,
+ this shift constant is valid for the host, and we can do arithmetic
+ in OP_MODE. */
+
+ if (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0
+ && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
+ && HWI_COMPUTABLE_MODE_P (op_mode))
+ {
+ rtx inner = XEXP (x, 0);
+ unsigned HOST_WIDE_INT inner_mask;
+
+ /* Select the mask of the bits we need for the shift operand. */
+ inner_mask = mask << INTVAL (XEXP (x, 1));
+
+ /* We can only change the mode of the shift if we can do arithmetic
+ in the mode of the shift and INNER_MASK is no wider than the
+ width of X's mode. */
+ if ((inner_mask & ~GET_MODE_MASK (xmode)) != 0)
+ op_mode = xmode;
+
+ inner = force_to_mode (inner, op_mode, inner_mask, next_select);
+
+ if (xmode != op_mode || inner != XEXP (x, 0))
+ {
+ x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
+ xmode = op_mode;
+ }
+ }
+
+ /* If we have (and (lshiftrt FOO C1) C2) where the combination of the
+ shift and AND produces only copies of the sign bit (C2 is one less
+ than a power of two), we can do this with just a shift. */
+
+ if (GET_CODE (x) == LSHIFTRT
+ && CONST_INT_P (XEXP (x, 1))
+ /* The shift puts one of the sign bit copies in the least significant
+ bit. */
+ && ((INTVAL (XEXP (x, 1))
+ + num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
+ >= GET_MODE_PRECISION (xmode))
+ && pow2p_hwi (mask + 1)
+ /* Number of bits left after the shift must be more than the mask
+ needs. */
+ && ((INTVAL (XEXP (x, 1)) + exact_log2 (mask + 1))
+ <= GET_MODE_PRECISION (xmode))
+ /* Must be more sign bit copies than the mask needs. */
+ && ((int) num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+ >= exact_log2 (mask + 1)))
+ {
+ int nbits = GET_MODE_PRECISION (xmode) - exact_log2 (mask + 1);
+ x = simplify_gen_binary (LSHIFTRT, xmode, XEXP (x, 0),
+ gen_int_shift_amount (xmode, nbits));
+ }
+ goto shiftrt;
+
+ case ASHIFTRT:
+ /* If we are just looking for the sign bit, we don't need this shift at
+ all, even if it has a variable count. */
+ if (val_signbit_p (xmode, mask))
+ return force_to_mode (XEXP (x, 0), mode, mask, next_select);
+
+ /* If this is a shift by a constant, get a mask that contains those bits
+ that are not copies of the sign bit. We then have two cases: If
+ MASK only includes those bits, this can be a logical shift, which may
+ allow simplifications. If MASK is a single-bit field not within
+ those bits, we are requesting a copy of the sign bit and hence can
+ shift the sign bit to the appropriate location. */
+
+ if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0
+ && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
+ {
+ unsigned HOST_WIDE_INT nonzero;
+ int i;
+
+ /* If the considered data is wider than HOST_WIDE_INT, we can't
+ represent a mask for all its bits in a single scalar.
+ But we only care about the lower bits, so calculate these. */
+
+ if (GET_MODE_PRECISION (xmode) > HOST_BITS_PER_WIDE_INT)
+ {
+ nonzero = HOST_WIDE_INT_M1U;
+
+ /* GET_MODE_PRECISION (GET_MODE (x)) - INTVAL (XEXP (x, 1))
+ is the number of bits a full-width mask would have set.
+ We need only shift if these are fewer than nonzero can
+ hold. If not, we must keep all bits set in nonzero. */
+
+ if (GET_MODE_PRECISION (xmode) - INTVAL (XEXP (x, 1))
+ < HOST_BITS_PER_WIDE_INT)
+ nonzero >>= INTVAL (XEXP (x, 1))
+ + HOST_BITS_PER_WIDE_INT
+ - GET_MODE_PRECISION (xmode);
+ }
+ else
+ {
+ nonzero = GET_MODE_MASK (xmode);
+ nonzero >>= INTVAL (XEXP (x, 1));
+ }
+
+ if ((mask & ~nonzero) == 0)
+ {
+ x = simplify_shift_const (NULL_RTX, LSHIFTRT, xmode,
+ XEXP (x, 0), INTVAL (XEXP (x, 1)));
+ if (GET_CODE (x) != ASHIFTRT)
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ else if ((i = exact_log2 (mask)) >= 0)
+ {
+ x = simplify_shift_const
+ (NULL_RTX, LSHIFTRT, xmode, XEXP (x, 0),
+ GET_MODE_PRECISION (xmode) - 1 - i);
+
+ if (GET_CODE (x) != ASHIFTRT)
+ return force_to_mode (x, mode, mask, next_select);
+ }
+ }
+
+ /* If MASK is 1, convert this to an LSHIFTRT. This can be done
+ even if the shift count isn't a constant. */
+ if (mask == 1)
+ x = simplify_gen_binary (LSHIFTRT, xmode, XEXP (x, 0), XEXP (x, 1));
+
+ shiftrt:
+
+ /* If this is a zero- or sign-extension operation that just affects bits
+ we don't care about, remove it. Be sure the call above returned
+ something that is still a shift. */
+
+ if ((GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ASHIFTRT)
+ && CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0
+ && (INTVAL (XEXP (x, 1))
+ <= GET_MODE_PRECISION (xmode) - (floor_log2 (mask) + 1))
+ && GET_CODE (XEXP (x, 0)) == ASHIFT
+ && XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
+ return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
+ next_select);
+
+ break;
+
+ case ROTATE:
+ case ROTATERT:
+ /* If the shift count is constant and we can do computations
+ in the mode of X, compute where the bits we care about are.
+ Otherwise, we can't do anything. Don't change the mode of
+ the shift or propagate MODE into the shift, though. */
+ if (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0)
+ {
+ temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE,
+ xmode, gen_int_mode (mask, xmode),
+ XEXP (x, 1));
+ if (temp && CONST_INT_P (temp))
+ x = simplify_gen_binary (code, xmode,
+ force_to_mode (XEXP (x, 0), xmode,
+ INTVAL (temp), next_select),
+ XEXP (x, 1));
+ }
+ break;
+
+ case NEG:
+ /* If we just want the low-order bit, the NEG isn't needed since it
+ won't change the low-order bit. */
+ if (mask == 1)
+ return force_to_mode (XEXP (x, 0), mode, mask, just_select);
+
+ /* We need any bits less significant than the most significant bit in
+ MASK since carries from those bits will affect the bits we are
+ interested in. */
+ mask = fuller_mask;
+ goto unop;
+
+ case NOT:
+ /* (not FOO) is (xor FOO CONST), so if FOO is an LSHIFTRT, we can do the
+ same as the XOR case above. Ensure that the constant we form is not
+ wider than the mode of X. */
+
+ if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
+ && (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask)
+ < GET_MODE_PRECISION (xmode))
+ && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT)
+ {
+ temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)), xmode);
+ temp = simplify_gen_binary (XOR, xmode, XEXP (XEXP (x, 0), 0), temp);
+ x = simplify_gen_binary (LSHIFTRT, xmode,
+ temp, XEXP (XEXP (x, 0), 1));
+
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
+ use the full mask inside the NOT. */
+ mask = fuller_mask;
+
+ unop:
+ op0 = gen_lowpart_or_truncate (op_mode,
+ force_to_mode (XEXP (x, 0), mode, mask,
+ next_select));
+ if (op_mode != xmode || op0 != XEXP (x, 0))
+ {
+ x = simplify_gen_unary (code, op_mode, op0, op_mode);
+ xmode = op_mode;
+ }
+ break;
+
+ case NE:
+ /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included
+ in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
+ which is equal to STORE_FLAG_VALUE. */
+ if ((mask & ~STORE_FLAG_VALUE) == 0
+ && XEXP (x, 1) == const0_rtx
+ && GET_MODE (XEXP (x, 0)) == mode
+ && pow2p_hwi (nonzero_bits (XEXP (x, 0), mode))
+ && (nonzero_bits (XEXP (x, 0), mode)
+ == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
+ return force_to_mode (XEXP (x, 0), mode, mask, next_select);
+
+ break;
+
+ case IF_THEN_ELSE:
+ /* We have no way of knowing if the IF_THEN_ELSE can itself be
+ written in a narrower mode. We play it safe and do not do so. */
+
+ op0 = gen_lowpart_or_truncate (xmode,
+ force_to_mode (XEXP (x, 1), mode,
+ mask, next_select));
+ op1 = gen_lowpart_or_truncate (xmode,
+ force_to_mode (XEXP (x, 2), mode,
+ mask, next_select));
+ if (op0 != XEXP (x, 1) || op1 != XEXP (x, 2))
+ x = simplify_gen_ternary (IF_THEN_ELSE, xmode,
+ GET_MODE (XEXP (x, 0)), XEXP (x, 0),
+ op0, op1);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Ensure we return a value of the proper mode. */
+ return gen_lowpart_or_truncate (mode, x);
+}
+
+/* Return nonzero if X is an expression that has one of two values depending on
+ whether some other value is zero or nonzero. In that case, we return the
+ value that is being tested, *PTRUE is set to the value if the rtx being
+ returned has a nonzero value, and *PFALSE is set to the other alternative.
+
+ If we return zero, we set *PTRUE and *PFALSE to X. */
+
+static rtx
+if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
+{
+ machine_mode mode = GET_MODE (x);
+ enum rtx_code code = GET_CODE (x);
+ rtx cond0, cond1, true0, true1, false0, false1;
+ unsigned HOST_WIDE_INT nz;
+ scalar_int_mode int_mode;
+
+ /* If we are comparing a value against zero, we are done. */
+ if ((code == NE || code == EQ)
+ && XEXP (x, 1) == const0_rtx)
+ {
+ *ptrue = (code == NE) ? const_true_rtx : const0_rtx;
+ *pfalse = (code == NE) ? const0_rtx : const_true_rtx;
+ return XEXP (x, 0);
+ }
+
+ /* If this is a unary operation whose operand has one of two values, apply
+ our opcode to compute those values. */
+ else if (UNARY_P (x)
+ && (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
+ {
+ *ptrue = simplify_gen_unary (code, mode, true0, GET_MODE (XEXP (x, 0)));
+ *pfalse = simplify_gen_unary (code, mode, false0,
+ GET_MODE (XEXP (x, 0)));
+ return cond0;
+ }
+
+ /* If this is a COMPARE, do nothing, since the IF_THEN_ELSE we would
+ make can't possibly match and would suppress other optimizations. */
+ else if (code == COMPARE)
+ ;
+
+ /* If this is a binary operation, see if either side has only one of two
+ values. If either one does or if both do and they are conditional on
+ the same value, compute the new true and false values. */
+ else if (BINARY_P (x))
+ {
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+ cond0 = if_then_else_cond (op0, &true0, &false0);
+ cond1 = if_then_else_cond (op1, &true1, &false1);
+
+ if ((cond0 != 0 && cond1 != 0 && !rtx_equal_p (cond0, cond1))
+ && (REG_P (op0) || REG_P (op1)))
+ {
+ /* Try to enable a simplification by undoing work done by
+ if_then_else_cond if it converted a REG into something more
+ complex. */
+ if (REG_P (op0))
+ {
+ cond0 = 0;
+ true0 = false0 = op0;
+ }
+ else
+ {
+ cond1 = 0;
+ true1 = false1 = op1;
+ }
+ }
+
+ if ((cond0 != 0 || cond1 != 0)
+ && ! (cond0 != 0 && cond1 != 0 && !rtx_equal_p (cond0, cond1)))
+ {
+ /* If if_then_else_cond returned zero, then true/false are the
+ same rtl. We must copy one of them to prevent invalid rtl
+ sharing. */
+ if (cond0 == 0)
+ true0 = copy_rtx (true0);
+ else if (cond1 == 0)
+ true1 = copy_rtx (true1);
+
+ if (COMPARISON_P (x))
+ {
+ *ptrue = simplify_gen_relational (code, mode, VOIDmode,
+ true0, true1);
+ *pfalse = simplify_gen_relational (code, mode, VOIDmode,
+ false0, false1);
+ }
+ else
+ {
+ *ptrue = simplify_gen_binary (code, mode, true0, true1);
+ *pfalse = simplify_gen_binary (code, mode, false0, false1);
+ }
+
+ return cond0 ? cond0 : cond1;
+ }
+
+ /* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the
+ operands is zero when the other is nonzero, and vice-versa,
+ and STORE_FLAG_VALUE is 1 or -1. */
+
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == PLUS || code == IOR || code == XOR || code == MINUS
+ || code == UMAX)
+ && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
+ {
+ rtx op0 = XEXP (XEXP (x, 0), 1);
+ rtx op1 = XEXP (XEXP (x, 1), 1);
+
+ cond0 = XEXP (XEXP (x, 0), 0);
+ cond1 = XEXP (XEXP (x, 1), 0);
+
+ if (COMPARISON_P (cond0)
+ && COMPARISON_P (cond1)
+ && SCALAR_INT_MODE_P (mode)
+ && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
+ && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
+ && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
+ || ((swap_condition (GET_CODE (cond0))
+ == reversed_comparison_code (cond1, NULL))
+ && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
+ && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
+ && ! side_effects_p (x))
+ {
+ *ptrue = simplify_gen_binary (MULT, mode, op0, const_true_rtx);
+ *pfalse = simplify_gen_binary (MULT, mode,
+ (code == MINUS
+ ? simplify_gen_unary (NEG, mode,
+ op1, mode)
+ : op1),
+ const_true_rtx);
+ return cond0;
+ }
+ }
+
+ /* Similarly for MULT, AND and UMIN, except that for these the result
+ is always zero. */
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == MULT || code == AND || code == UMIN)
+ && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
+ {
+ cond0 = XEXP (XEXP (x, 0), 0);
+ cond1 = XEXP (XEXP (x, 1), 0);
+
+ if (COMPARISON_P (cond0)
+ && COMPARISON_P (cond1)
+ && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
+ && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
+ && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
+ || ((swap_condition (GET_CODE (cond0))
+ == reversed_comparison_code (cond1, NULL))
+ && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
+ && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
+ && ! side_effects_p (x))
+ {
+ *ptrue = *pfalse = const0_rtx;
+ return cond0;
+ }
+ }
+ }
+
+ else if (code == IF_THEN_ELSE)
+ {
+ /* If we have IF_THEN_ELSE already, extract the condition and
+ canonicalize it if it is NE or EQ. */
+ cond0 = XEXP (x, 0);
+ *ptrue = XEXP (x, 1), *pfalse = XEXP (x, 2);
+ if (GET_CODE (cond0) == NE && XEXP (cond0, 1) == const0_rtx)
+ return XEXP (cond0, 0);
+ else if (GET_CODE (cond0) == EQ && XEXP (cond0, 1) == const0_rtx)
+ {
+ *ptrue = XEXP (x, 2), *pfalse = XEXP (x, 1);
+ return XEXP (cond0, 0);
+ }
+ else
+ return cond0;
+ }
+
+ /* If X is a SUBREG, we can narrow both the true and false values
+ if the inner expression, if there is a condition. */
+ else if (code == SUBREG
+ && (cond0 = if_then_else_cond (SUBREG_REG (x), &true0,
+ &false0)) != 0)
+ {
+ true0 = simplify_gen_subreg (mode, true0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+ false0 = simplify_gen_subreg (mode, false0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+ if (true0 && false0)
+ {
+ *ptrue = true0;
+ *pfalse = false0;
+ return cond0;
+ }
+ }
+
+ /* If X is a constant, this isn't special and will cause confusions
+ if we treat it as such. Likewise if it is equivalent to a constant. */
+ else if (CONSTANT_P (x)
+ || ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
+ ;
+
+ /* If we're in BImode, canonicalize on 0 and STORE_FLAG_VALUE, as that
+ will be least confusing to the rest of the compiler. */
+ else if (mode == BImode)
+ {
+ *ptrue = GEN_INT (STORE_FLAG_VALUE), *pfalse = const0_rtx;
+ return x;
+ }
+
+ /* If X is known to be either 0 or -1, those are the true and
+ false values when testing X. */
+ else if (x == constm1_rtx || x == const0_rtx
+ || (is_a <scalar_int_mode> (mode, &int_mode)
+ && (num_sign_bit_copies (x, int_mode)
+ == GET_MODE_PRECISION (int_mode))))
+ {
+ *ptrue = constm1_rtx, *pfalse = const0_rtx;
+ return x;
+ }
+
+ /* Likewise for 0 or a single bit. */
+ else if (HWI_COMPUTABLE_MODE_P (mode)
+ && pow2p_hwi (nz = nonzero_bits (x, mode)))
+ {
+ *ptrue = gen_int_mode (nz, mode), *pfalse = const0_rtx;
+ return x;
+ }
+
+ /* Otherwise fail; show no condition with true and false values the same. */
+ *ptrue = *pfalse = x;
+ return 0;
+}
+
+/* Return the value of expression X given the fact that condition COND
+ is known to be true when applied to REG as its first operand and VAL
+ as its second. X is known to not be shared and so can be modified in
+ place.
+
+ We only handle the simplest cases, and specifically those cases that
+ arise with IF_THEN_ELSE expressions. */
+
+static rtx
+known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt;
+ int i, j;
+
+ if (side_effects_p (x))
+ return x;
+
+ /* If either operand of the condition is a floating point value,
+ then we have to avoid collapsing an EQ comparison. */
+ if (cond == EQ
+ && rtx_equal_p (x, reg)
+ && ! FLOAT_MODE_P (GET_MODE (x))
+ && ! FLOAT_MODE_P (GET_MODE (val)))
+ return val;
+
+ if (cond == UNEQ && rtx_equal_p (x, reg))
+ return val;
+
+ /* If X is (abs REG) and we know something about REG's relationship
+ with zero, we may be able to simplify this. */
+
+ if (code == ABS && rtx_equal_p (XEXP (x, 0), reg) && val == const0_rtx)
+ switch (cond)
+ {
+ case GE: case GT: case EQ:
+ return XEXP (x, 0);
+ case LT: case LE:
+ return simplify_gen_unary (NEG, GET_MODE (XEXP (x, 0)),
+ XEXP (x, 0),
+ GET_MODE (XEXP (x, 0)));
+ default:
+ break;
+ }
+
+ /* The only other cases we handle are MIN, MAX, and comparisons if the
+ operands are the same as REG and VAL. */
+
+ else if (COMPARISON_P (x) || COMMUTATIVE_ARITH_P (x))
+ {
+ if (rtx_equal_p (XEXP (x, 0), val))
+ {
+ std::swap (val, reg);
+ cond = swap_condition (cond);
+ }
+
+ if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
+ {
+ if (COMPARISON_P (x))
+ {
+ if (comparison_dominates_p (cond, code))
+ return VECTOR_MODE_P (GET_MODE (x)) ? x : const_true_rtx;
+
+ code = reversed_comparison_code (x, NULL);
+ if (code != UNKNOWN
+ && comparison_dominates_p (cond, code))
+ return CONST0_RTX (GET_MODE (x));
+ else
+ return x;
+ }
+ else if (code == SMAX || code == SMIN
+ || code == UMIN || code == UMAX)
+ {
+ int unsignedp = (code == UMIN || code == UMAX);
+
+ /* Do not reverse the condition when it is NE or EQ.
+ This is because we cannot conclude anything about
+ the value of 'SMAX (x, y)' when x is not equal to y,
+ but we can when x equals y. */
+ if ((code == SMAX || code == UMAX)
+ && ! (cond == EQ || cond == NE))
+ cond = reverse_condition (cond);
+
+ switch (cond)
+ {
+ case GE: case GT:
+ return unsignedp ? x : XEXP (x, 1);
+ case LE: case LT:
+ return unsignedp ? x : XEXP (x, 0);
+ case GEU: case GTU:
+ return unsignedp ? XEXP (x, 1) : x;
+ case LEU: case LTU:
+ return unsignedp ? XEXP (x, 0) : x;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ else if (code == SUBREG)
+ {
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
+ rtx new_rtx, r = known_cond (SUBREG_REG (x), cond, reg, val);
+
+ if (SUBREG_REG (x) != r)
+ {
+ /* We must simplify subreg here, before we lose track of the
+ original inner_mode. */
+ new_rtx = simplify_subreg (GET_MODE (x), r,
+ inner_mode, SUBREG_BYTE (x));
+ if (new_rtx)
+ return new_rtx;
+ else
+ SUBST (SUBREG_REG (x), r);
+ }
+
+ return x;
+ }
+ /* We don't have to handle SIGN_EXTEND here, because even in the
+ case of replacing something with a modeless CONST_INT, a
+ CONST_INT is already (supposed to be) a valid sign extension for
+ its narrower mode, which implies it's already properly
+ sign-extended for the wider mode. Now, for ZERO_EXTEND, the
+ story is different. */
+ else if (code == ZERO_EXTEND)
+ {
+ machine_mode inner_mode = GET_MODE (XEXP (x, 0));
+ rtx new_rtx, r = known_cond (XEXP (x, 0), cond, reg, val);
+
+ if (XEXP (x, 0) != r)
+ {
+ /* We must simplify the zero_extend here, before we lose
+ track of the original inner_mode. */
+ new_rtx = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+ r, inner_mode);
+ if (new_rtx)
+ return new_rtx;
+ else
+ SUBST (XEXP (x, 0), r);
+ }
+
+ return x;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ SUBST (XEXP (x, i), known_cond (XEXP (x, i), cond, reg, val));
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ SUBST (XVECEXP (x, i, j), known_cond (XVECEXP (x, i, j),
+ cond, reg, val));
+ }
+
+ return x;
+}
+
+/* See if X and Y are equal for the purposes of seeing if we can rewrite an
+ assignment as a field assignment. */
+
+static int
+rtx_equal_for_field_assignment_p (rtx x, rtx y, bool widen_x)
+{
+ if (widen_x && GET_MODE (x) != GET_MODE (y))
+ {
+ if (paradoxical_subreg_p (GET_MODE (x), GET_MODE (y)))
+ return 0;
+ if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ return 0;
+ x = adjust_address_nv (x, GET_MODE (y),
+ byte_lowpart_offset (GET_MODE (y),
+ GET_MODE (x)));
+ }
+
+ if (x == y || rtx_equal_p (x, y))
+ return 1;
+
+ if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ /* Check for a paradoxical SUBREG of a MEM compared with the MEM.
+ Note that all SUBREGs of MEM are paradoxical; otherwise they
+ would have been rewritten. */
+ if (MEM_P (x) && GET_CODE (y) == SUBREG
+ && MEM_P (SUBREG_REG (y))
+ && rtx_equal_p (SUBREG_REG (y),
+ gen_lowpart (GET_MODE (SUBREG_REG (y)), x)))
+ return 1;
+
+ if (MEM_P (y) && GET_CODE (x) == SUBREG
+ && MEM_P (SUBREG_REG (x))
+ && rtx_equal_p (SUBREG_REG (x),
+ gen_lowpart (GET_MODE (SUBREG_REG (x)), y)))
+ return 1;
+
+ /* We used to see if get_last_value of X and Y were the same but that's
+ not correct. In one direction, we'll cause the assignment to have
+ the wrong destination and in the case, we'll import a register into this
+ insn that might have already have been dead. So fail if none of the
+ above cases are true. */
+ return 0;
+}
+
+/* See if X, a SET operation, can be rewritten as a bit-field assignment.
+ Return that assignment if so.
+
+ We only handle the most common cases. */
+
+static rtx
+make_field_assignment (rtx x)
+{
+ rtx dest = SET_DEST (x);
+ rtx src = SET_SRC (x);
+ rtx assign;
+ rtx rhs, lhs;
+ HOST_WIDE_INT c1;
+ HOST_WIDE_INT pos;
+ unsigned HOST_WIDE_INT len;
+ rtx other;
+
+ /* All the rules in this function are specific to scalar integers. */
+ scalar_int_mode mode;
+ if (!is_a <scalar_int_mode> (GET_MODE (dest), &mode))
+ return x;
+
+ /* If SRC was (and (not (ashift (const_int 1) POS)) DEST), this is
+ a clear of a one-bit field. We will have changed it to
+ (and (rotate (const_int -2) POS) DEST), so check for that. Also check
+ for a SUBREG. */
+
+ if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
+ && CONST_INT_P (XEXP (XEXP (src, 0), 0))
+ && INTVAL (XEXP (XEXP (src, 0), 0)) == -2
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
+ {
+ assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
+ 1, 1, 1, 0);
+ if (assign != 0)
+ return gen_rtx_SET (assign, const0_rtx);
+ return x;
+ }
+
+ if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (src, 0))
+ && partial_subreg_p (XEXP (src, 0))
+ && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
+ && CONST_INT_P (XEXP (SUBREG_REG (XEXP (src, 0)), 0))
+ && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
+ {
+ assign = make_extraction (VOIDmode, dest, 0,
+ XEXP (SUBREG_REG (XEXP (src, 0)), 1),
+ 1, 1, 1, 0);
+ if (assign != 0)
+ return gen_rtx_SET (assign, const0_rtx);
+ return x;
+ }
+
+ /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a
+ one-bit field. */
+ if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
+ && XEXP (XEXP (src, 0), 0) == const1_rtx
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
+ {
+ assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
+ 1, 1, 1, 0);
+ if (assign != 0)
+ return gen_rtx_SET (assign, const1_rtx);
+ return x;
+ }
+
+ /* If DEST is already a field assignment, i.e. ZERO_EXTRACT, and the
+ SRC is an AND with all bits of that field set, then we can discard
+ the AND. */
+ if (GET_CODE (dest) == ZERO_EXTRACT
+ && CONST_INT_P (XEXP (dest, 1))
+ && GET_CODE (src) == AND
+ && CONST_INT_P (XEXP (src, 1)))
+ {
+ HOST_WIDE_INT width = INTVAL (XEXP (dest, 1));
+ unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1));
+ unsigned HOST_WIDE_INT ze_mask;
+
+ if (width >= HOST_BITS_PER_WIDE_INT)
+ ze_mask = -1;
+ else
+ ze_mask = ((unsigned HOST_WIDE_INT)1 << width) - 1;
+
+ /* Complete overlap. We can remove the source AND. */
+ if ((and_mask & ze_mask) == ze_mask)
+ return gen_rtx_SET (dest, XEXP (src, 0));
+
+ /* Partial overlap. We can reduce the source AND. */
+ if ((and_mask & ze_mask) != and_mask)
+ {
+ src = gen_rtx_AND (mode, XEXP (src, 0),
+ gen_int_mode (and_mask & ze_mask, mode));
+ return gen_rtx_SET (dest, src);
+ }
+ }
+
+ /* The other case we handle is assignments into a constant-position
+ field. They look like (ior/xor (and DEST C1) OTHER). If C1 represents
+ a mask that has all one bits except for a group of zero bits and
+ OTHER is known to have zeros where C1 has ones, this is such an
+ assignment. Compute the position and length from C1. Shift OTHER
+ to the appropriate position, force it to the required mode, and
+ make the extraction. Check for the AND in both operands. */
+
+ /* One or more SUBREGs might obscure the constant-position field
+ assignment. The first one we are likely to encounter is an outer
+ narrowing SUBREG, which we can just strip for the purposes of
+ identifying the constant-field assignment. */
+ scalar_int_mode src_mode = mode;
+ if (GET_CODE (src) == SUBREG
+ && subreg_lowpart_p (src)
+ && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (src)), &src_mode))
+ src = SUBREG_REG (src);
+
+ if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
+ return x;
+
+ rhs = expand_compound_operation (XEXP (src, 0));
+ lhs = expand_compound_operation (XEXP (src, 1));
+
+ if (GET_CODE (rhs) == AND
+ && CONST_INT_P (XEXP (rhs, 1))
+ && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
+ c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
+ /* The second SUBREG that might get in the way is a paradoxical
+ SUBREG around the first operand of the AND. We want to
+ pretend the operand is as wide as the destination here. We
+ do this by adjusting the MEM to wider mode for the sole
+ purpose of the call to rtx_equal_for_field_assignment_p. Also
+ note this trick only works for MEMs. */
+ else if (GET_CODE (rhs) == AND
+ && paradoxical_subreg_p (XEXP (rhs, 0))
+ && MEM_P (SUBREG_REG (XEXP (rhs, 0)))
+ && CONST_INT_P (XEXP (rhs, 1))
+ && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (rhs, 0)),
+ dest, true))
+ c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
+ else if (GET_CODE (lhs) == AND
+ && CONST_INT_P (XEXP (lhs, 1))
+ && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
+ c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
+ /* The second SUBREG that might get in the way is a paradoxical
+ SUBREG around the first operand of the AND. We want to
+ pretend the operand is as wide as the destination here. We
+ do this by adjusting the MEM to wider mode for the sole
+ purpose of the call to rtx_equal_for_field_assignment_p. Also
+ note this trick only works for MEMs. */
+ else if (GET_CODE (lhs) == AND
+ && paradoxical_subreg_p (XEXP (lhs, 0))
+ && MEM_P (SUBREG_REG (XEXP (lhs, 0)))
+ && CONST_INT_P (XEXP (lhs, 1))
+ && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (lhs, 0)),
+ dest, true))
+ c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
+ else
+ return x;
+
+ pos = get_pos_from_mask ((~c1) & GET_MODE_MASK (mode), &len);
+ if (pos < 0
+ || pos + len > GET_MODE_PRECISION (mode)
+ || GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT
+ || (c1 & nonzero_bits (other, mode)) != 0)
+ return x;
+
+ assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
+ if (assign == 0)
+ return x;
+
+ /* The mode to use for the source is the mode of the assignment, or of
+ what is inside a possible STRICT_LOW_PART. */
+ machine_mode new_mode = (GET_CODE (assign) == STRICT_LOW_PART
+ ? GET_MODE (XEXP (assign, 0)) : GET_MODE (assign));
+
+ /* Shift OTHER right POS places and make it the source, restricting it
+ to the proper length and mode. */
+
+ src = canon_reg_for_combine (simplify_shift_const (NULL_RTX, LSHIFTRT,
+ src_mode, other, pos),
+ dest);
+ src = force_to_mode (src, new_mode,
+ len >= HOST_BITS_PER_WIDE_INT
+ ? HOST_WIDE_INT_M1U
+ : (HOST_WIDE_INT_1U << len) - 1,
+ 0);
+
+ /* If SRC is masked by an AND that does not make a difference in
+ the value being stored, strip it. */
+ if (GET_CODE (assign) == ZERO_EXTRACT
+ && CONST_INT_P (XEXP (assign, 1))
+ && INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
+ && GET_CODE (src) == AND
+ && CONST_INT_P (XEXP (src, 1))
+ && UINTVAL (XEXP (src, 1))
+ == (HOST_WIDE_INT_1U << INTVAL (XEXP (assign, 1))) - 1)
+ src = XEXP (src, 0);
+
+ return gen_rtx_SET (assign, src);
+}
+
+/* See if X is of the form (+ (* a c) (* b c)) and convert to (* (+ a b) c)
+ if so. */
+
+static rtx
+apply_distributive_law (rtx x)
+{
+ enum rtx_code code = GET_CODE (x);
+ enum rtx_code inner_code;
+ rtx lhs, rhs, other;
+ rtx tem;
+
+ /* Distributivity is not true for floating point as it can change the
+ value. So we don't do it unless -funsafe-math-optimizations. */
+ if (FLOAT_MODE_P (GET_MODE (x))
+ && ! flag_unsafe_math_optimizations)
+ return x;
+
+ /* The outer operation can only be one of the following: */
+ if (code != IOR && code != AND && code != XOR
+ && code != PLUS && code != MINUS)
+ return x;
+
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
+
+ /* If either operand is a primitive we can't do anything, so get out
+ fast. */
+ if (OBJECT_P (lhs) || OBJECT_P (rhs))
+ return x;
+
+ lhs = expand_compound_operation (lhs);
+ rhs = expand_compound_operation (rhs);
+ inner_code = GET_CODE (lhs);
+ if (inner_code != GET_CODE (rhs))
+ return x;
+
+ /* See if the inner and outer operations distribute. */
+ switch (inner_code)
+ {
+ case LSHIFTRT:
+ case ASHIFTRT:
+ case AND:
+ case IOR:
+ /* These all distribute except over PLUS. */
+ if (code == PLUS || code == MINUS)
+ return x;
+ break;
+
+ case MULT:
+ if (code != PLUS && code != MINUS)
+ return x;
+ break;
+
+ case ASHIFT:
+ /* This is also a multiply, so it distributes over everything. */
+ break;
+
+ /* This used to handle SUBREG, but this turned out to be counter-
+ productive, since (subreg (op ...)) usually is not handled by
+ insn patterns, and this "optimization" therefore transformed
+ recognizable patterns into unrecognizable ones. Therefore the
+ SUBREG case was removed from here.
+
+ It is possible that distributing SUBREG over arithmetic operations
+ leads to an intermediate result than can then be optimized further,
+ e.g. by moving the outer SUBREG to the other side of a SET as done
+ in simplify_set. This seems to have been the original intent of
+ handling SUBREGs here.
+
+ However, with current GCC this does not appear to actually happen,
+ at least on major platforms. If some case is found where removing
+ the SUBREG case here prevents follow-on optimizations, distributing
+ SUBREGs ought to be re-added at that place, e.g. in simplify_set. */
+
+ default:
+ return x;
+ }
+
+ /* Set LHS and RHS to the inner operands (A and B in the example
+ above) and set OTHER to the common operand (C in the example).
+ There is only one way to do this unless the inner operation is
+ commutative. */
+ if (COMMUTATIVE_ARITH_P (lhs)
+ && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 0)))
+ other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 1);
+ else if (COMMUTATIVE_ARITH_P (lhs)
+ && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 1)))
+ other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 0);
+ else if (COMMUTATIVE_ARITH_P (lhs)
+ && rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 0)))
+ other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 1);
+ else if (rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 1)))
+ other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 0);
+ else
+ return x;
+
+ /* Form the new inner operation, seeing if it simplifies first. */
+ tem = simplify_gen_binary (code, GET_MODE (x), lhs, rhs);
+
+ /* There is one exception to the general way of distributing:
+ (a | c) ^ (b | c) -> (a ^ b) & ~c */
+ if (code == XOR && inner_code == IOR)
+ {
+ inner_code = AND;
+ other = simplify_gen_unary (NOT, GET_MODE (x), other, GET_MODE (x));
+ }
+
+ /* We may be able to continuing distributing the result, so call
+ ourselves recursively on the inner operation before forming the
+ outer operation, which we return. */
+ return simplify_gen_binary (inner_code, GET_MODE (x),
+ apply_distributive_law (tem), other);
+}
+
+/* See if X is of the form (* (+ A B) C), and if so convert to
+ (+ (* A C) (* B C)) and try to simplify.
+
+ Most of the time, this results in no change. However, if some of
+ the operands are the same or inverses of each other, simplifications
+ will result.
+
+ For example, (and (ior A B) (not B)) can occur as the result of
+ expanding a bit field assignment. When we apply the distributive
+ law to this, we get (ior (and (A (not B))) (and (B (not B)))),
+ which then simplifies to (and (A (not B))).
+
+ Note that no checks happen on the validity of applying the inverse
+ distributive law. This is pointless since we can do it in the
+ few places where this routine is called.
+
+ N is the index of the term that is decomposed (the arithmetic operation,
+ i.e. (+ A B) in the first example above). !N is the index of the term that
+ is distributed, i.e. of C in the first example above. */
+static rtx
+distribute_and_simplify_rtx (rtx x, int n)
+{
+ machine_mode mode;
+ enum rtx_code outer_code, inner_code;
+ rtx decomposed, distributed, inner_op0, inner_op1, new_op0, new_op1, tmp;
+
+ /* Distributivity is not true for floating point as it can change the
+ value. So we don't do it unless -funsafe-math-optimizations. */
+ if (FLOAT_MODE_P (GET_MODE (x))
+ && ! flag_unsafe_math_optimizations)
+ return NULL_RTX;
+
+ decomposed = XEXP (x, n);
+ if (!ARITHMETIC_P (decomposed))
+ return NULL_RTX;
+
+ mode = GET_MODE (x);
+ outer_code = GET_CODE (x);
+ distributed = XEXP (x, !n);
+
+ inner_code = GET_CODE (decomposed);
+ inner_op0 = XEXP (decomposed, 0);
+ inner_op1 = XEXP (decomposed, 1);
+
+ /* Special case (and (xor B C) (not A)), which is equivalent to
+ (xor (ior A B) (ior A C)) */
+ if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT)
+ {
+ distributed = XEXP (distributed, 0);
+ outer_code = IOR;
+ }
+
+ if (n == 0)
+ {
+ /* Distribute the second term. */
+ new_op0 = simplify_gen_binary (outer_code, mode, inner_op0, distributed);
+ new_op1 = simplify_gen_binary (outer_code, mode, inner_op1, distributed);
+ }
+ else
+ {
+ /* Distribute the first term. */
+ new_op0 = simplify_gen_binary (outer_code, mode, distributed, inner_op0);
+ new_op1 = simplify_gen_binary (outer_code, mode, distributed, inner_op1);
+ }
+
+ tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
+ new_op0, new_op1));
+ if (GET_CODE (tmp) != outer_code
+ && (set_src_cost (tmp, mode, optimize_this_for_speed_p)
+ < set_src_cost (x, mode, optimize_this_for_speed_p)))
+ return tmp;
+
+ return NULL_RTX;
+}
+
+/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE. Return an equivalent form, if different from (and VAROP
+ (const_int CONSTOP)). Otherwise, return NULL_RTX. */
+
+static rtx
+simplify_and_const_int_1 (scalar_int_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
+{
+ unsigned HOST_WIDE_INT nonzero;
+ unsigned HOST_WIDE_INT orig_constop;
+ rtx orig_varop;
+ int i;
+
+ orig_varop = varop;
+ orig_constop = constop;
+ if (GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
+ /* Simplify VAROP knowing that we will be only looking at some of the
+ bits in it.
+
+ Note by passing in CONSTOP, we guarantee that the bits not set in
+ CONSTOP are not significant and will never be examined. We must
+ ensure that is the case by explicitly masking out those bits
+ before returning. */
+ varop = force_to_mode (varop, mode, constop, 0);
+
+ /* If VAROP is a CLOBBER, we will fail so return it. */
+ if (GET_CODE (varop) == CLOBBER)
+ return varop;
+
+ /* If VAROP is a CONST_INT, then we need to apply the mask in CONSTOP
+ to VAROP and return the new constant. */
+ if (CONST_INT_P (varop))
+ return gen_int_mode (INTVAL (varop) & constop, mode);
+
+ /* See what bits may be nonzero in VAROP. Unlike the general case of
+ a call to nonzero_bits, here we don't care about bits outside
+ MODE. */
+
+ nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
+
+ /* Turn off all bits in the constant that are known to already be zero.
+ Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
+ which is tested below. */
+
+ constop &= nonzero;
+
+ /* If we don't have any bits left, return zero. */
+ if (constop == 0 && !side_effects_p (varop))
+ return const0_rtx;
+
+ /* If VAROP is a NEG of something known to be zero or 1 and CONSTOP is
+ a power of two, we can replace this with an ASHIFT. */
+ if (GET_CODE (varop) == NEG && nonzero_bits (XEXP (varop, 0), mode) == 1
+ && (i = exact_log2 (constop)) >= 0)
+ return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (varop, 0), i);
+
+ /* If VAROP is an IOR or XOR, apply the AND to both branches of the IOR
+ or XOR, then try to apply the distributive law. This may eliminate
+ operations if either branch can be simplified because of the AND.
+ It may also make some cases more complex, but those cases probably
+ won't match a pattern either with or without this. */
+
+ if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR)
+ {
+ scalar_int_mode varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+ return
+ gen_lowpart
+ (mode,
+ apply_distributive_law
+ (simplify_gen_binary (GET_CODE (varop), varop_mode,
+ simplify_and_const_int (NULL_RTX, varop_mode,
+ XEXP (varop, 0),
+ constop),
+ simplify_and_const_int (NULL_RTX, varop_mode,
+ XEXP (varop, 1),
+ constop))));
+ }
+
+ /* If VAROP is PLUS, and the constant is a mask of low bits, distribute
+ the AND and see if one of the operands simplifies to zero. If so, we
+ may eliminate it. */
+
+ if (GET_CODE (varop) == PLUS
+ && pow2p_hwi (constop + 1))
+ {
+ rtx o0, o1;
+
+ o0 = simplify_and_const_int (NULL_RTX, mode, XEXP (varop, 0), constop);
+ o1 = simplify_and_const_int (NULL_RTX, mode, XEXP (varop, 1), constop);
+ if (o0 == const0_rtx)
+ return o1;
+ if (o1 == const0_rtx)
+ return o0;
+ }
+
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
+ /* If we are only masking insignificant bits, return VAROP. */
+ if (constop == nonzero)
+ return varop;
+
+ if (varop == orig_varop && constop == orig_constop)
+ return NULL_RTX;
+
+ /* Otherwise, return an AND. */
+ return simplify_gen_binary (AND, mode, varop, gen_int_mode (constop, mode));
+}
+
+
+/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE.
+
+ Return an equivalent form, if different from X. Otherwise, return X. If
+ X is zero, we are to always construct the equivalent form. */
+
+static rtx
+simplify_and_const_int (rtx x, scalar_int_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
+{
+ rtx tem = simplify_and_const_int_1 (mode, varop, constop);
+ if (tem)
+ return tem;
+
+ if (!x)
+ x = simplify_gen_binary (AND, GET_MODE (varop), varop,
+ gen_int_mode (constop, mode));
+ if (GET_MODE (x) != mode)
+ x = gen_lowpart (mode, x);
+ return x;
+}
+
+/* Given a REG X of mode XMODE, compute which bits in X can be nonzero.
+ We don't care about bits outside of those defined in MODE.
+ We DO care about all the bits in MODE, even if XMODE is smaller than MODE.
+
+ For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
+ a shift, AND, or zero_extract, we can do better. */
+
+static rtx
+reg_nonzero_bits_for_combine (const_rtx x, scalar_int_mode xmode,
+ scalar_int_mode mode,
+ unsigned HOST_WIDE_INT *nonzero)
+{
+ rtx tem;
+ reg_stat_type *rsp;
+
+ /* If X is a register whose nonzero bits value is current, use it.
+ Otherwise, if X is a register whose value we can find, use that
+ value. Otherwise, use the previously-computed global nonzero bits
+ for this register. */
+
+ rsp = &reg_stat[REGNO (x)];
+ if (rsp->last_set_value != 0
+ && (rsp->last_set_mode == mode
+ || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+ && GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
+ && GET_MODE_CLASS (mode) == MODE_INT))
+ && ((rsp->last_set_label >= label_tick_ebb_start
+ && rsp->last_set_label < label_tick)
+ || (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
+ || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+ && REGNO (x) < reg_n_sets_max
+ && REG_N_SETS (REGNO (x)) == 1
+ && !REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb),
+ REGNO (x)))))
+ {
+ /* Note that, even if the precision of last_set_mode is lower than that
+ of mode, record_value_for_reg invoked nonzero_bits on the register
+ with nonzero_bits_mode (because last_set_mode is necessarily integral
+ and HWI_COMPUTABLE_MODE_P in this case) so bits in nonzero_bits_mode
+ are all valid, hence in mode too since nonzero_bits_mode is defined
+ to the largest HWI_COMPUTABLE_MODE_P mode. */
+ *nonzero &= rsp->last_set_nonzero_bits;
+ return NULL;
+ }
+
+ tem = get_last_value (x);
+ if (tem)
+ {
+ if (SHORT_IMMEDIATES_SIGN_EXTEND)
+ tem = sign_extend_short_imm (tem, xmode, GET_MODE_PRECISION (mode));
+
+ return tem;
+ }
+
+ if (nonzero_sign_valid && rsp->nonzero_bits)
+ {
+ unsigned HOST_WIDE_INT mask = rsp->nonzero_bits;
+
+ if (GET_MODE_PRECISION (xmode) < GET_MODE_PRECISION (mode))
+ /* We don't know anything about the upper bits. */
+ mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (xmode);
+
+ *nonzero &= mask;
+ }
+
+ return NULL;
+}
+
+/* Given a reg X of mode XMODE, return the number of bits at the high-order
+ end of X that are known to be equal to the sign bit. X will be used
+ in mode MODE; the returned value will always be between 1 and the
+ number of bits in MODE. */
+
+static rtx
+reg_num_sign_bit_copies_for_combine (const_rtx x, scalar_int_mode xmode,
+ scalar_int_mode mode,
+ unsigned int *result)
+{
+ rtx tem;
+ reg_stat_type *rsp;
+
+ rsp = &reg_stat[REGNO (x)];
+ if (rsp->last_set_value != 0
+ && rsp->last_set_mode == mode
+ && ((rsp->last_set_label >= label_tick_ebb_start
+ && rsp->last_set_label < label_tick)
+ || (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
+ || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+ && REGNO (x) < reg_n_sets_max
+ && REG_N_SETS (REGNO (x)) == 1
+ && !REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb),
+ REGNO (x)))))
+ {
+ *result = rsp->last_set_sign_bit_copies;
+ return NULL;
+ }
+
+ tem = get_last_value (x);
+ if (tem != 0)
+ return tem;
+
+ if (nonzero_sign_valid && rsp->sign_bit_copies != 0
+ && GET_MODE_PRECISION (xmode) == GET_MODE_PRECISION (mode))
+ *result = rsp->sign_bit_copies;
+
+ return NULL;
+}
+
+/* Return the number of "extended" bits there are in X, when interpreted
+ as a quantity in MODE whose signedness is indicated by UNSIGNEDP. For
+ unsigned quantities, this is the number of high-order zero bits.
+ For signed quantities, this is the number of copies of the sign bit
+ minus 1. In both case, this function returns the number of "spare"
+ bits. For example, if two quantities for which this function returns
+ at least 1 are added, the addition is known not to overflow.
+
+ This function will always return 0 unless called during combine, which
+ implies that it must be called from a define_split. */
+
+unsigned int
+extended_count (const_rtx x, machine_mode mode, int unsignedp)
+{
+ if (nonzero_sign_valid == 0)
+ return 0;
+
+ scalar_int_mode int_mode;
+ return (unsignedp
+ ? (is_a <scalar_int_mode> (mode, &int_mode)
+ && HWI_COMPUTABLE_MODE_P (int_mode)
+ ? (unsigned int) (GET_MODE_PRECISION (int_mode) - 1
+ - floor_log2 (nonzero_bits (x, int_mode)))
+ : 0)
+ : num_sign_bit_copies (x, mode) - 1);
+}
+
+/* This function is called from `simplify_shift_const' to merge two
+ outer operations. Specifically, we have already found that we need
+ to perform operation *POP0 with constant *PCONST0 at the outermost
+ position. We would now like to also perform OP1 with constant CONST1
+ (with *POP0 being done last).
+
+ Return 1 if we can do the operation and update *POP0 and *PCONST0 with
+ the resulting operation. *PCOMP_P is set to 1 if we would need to
+ complement the innermost operand, otherwise it is unchanged.
+
+ MODE is the mode in which the operation will be done. No bits outside
+ the width of this mode matter. It is assumed that the width of this mode
+ is smaller than or equal to HOST_BITS_PER_WIDE_INT.
+
+ If *POP0 or OP1 are UNKNOWN, it means no operation is required. Only NEG, PLUS,
+ IOR, XOR, and AND are supported. We may set *POP0 to SET if the proper
+ result is simply *PCONST0.
+
+ If the resulting operation cannot be expressed as one operation, we
+ return 0 and do not change *POP0, *PCONST0, and *PCOMP_P. */
+
+static int
+merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1, HOST_WIDE_INT const1, machine_mode mode, int *pcomp_p)
+{
+ enum rtx_code op0 = *pop0;
+ HOST_WIDE_INT const0 = *pconst0;
+
+ const0 &= GET_MODE_MASK (mode);
+ const1 &= GET_MODE_MASK (mode);
+
+ /* If OP0 is an AND, clear unimportant bits in CONST1. */
+ if (op0 == AND)
+ const1 &= const0;
+
+ /* If OP0 or OP1 is UNKNOWN, this is easy. Similarly if they are the same or
+ if OP0 is SET. */
+
+ if (op1 == UNKNOWN || op0 == SET)
+ return 1;
+
+ else if (op0 == UNKNOWN)
+ op0 = op1, const0 = const1;
+
+ else if (op0 == op1)
+ {
+ switch (op0)
+ {
+ case AND:
+ const0 &= const1;
+ break;
+ case IOR:
+ const0 |= const1;
+ break;
+ case XOR:
+ const0 ^= const1;
+ break;
+ case PLUS:
+ const0 += const1;
+ break;
+ case NEG:
+ op0 = UNKNOWN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Otherwise, if either is a PLUS or NEG, we can't do anything. */
+ else if (op0 == PLUS || op1 == PLUS || op0 == NEG || op1 == NEG)
+ return 0;
+
+ /* If the two constants aren't the same, we can't do anything. The
+ remaining six cases can all be done. */
+ else if (const0 != const1)
+ return 0;
+
+ else
+ switch (op0)
+ {
+ case IOR:
+ if (op1 == AND)
+ /* (a & b) | b == b */
+ op0 = SET;
+ else /* op1 == XOR */
+ /* (a ^ b) | b == a | b */
+ {;}
+ break;
+
+ case XOR:
+ if (op1 == AND)
+ /* (a & b) ^ b == (~a) & b */
+ op0 = AND, *pcomp_p = 1;
+ else /* op1 == IOR */
+ /* (a | b) ^ b == a & ~b */
+ op0 = AND, const0 = ~const0;
+ break;
+
+ case AND:
+ if (op1 == IOR)
+ /* (a | b) & b == b */
+ op0 = SET;
+ else /* op1 == XOR */
+ /* (a ^ b) & b) == (~a) & b */
+ *pcomp_p = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for NO-OP cases. */
+ const0 &= GET_MODE_MASK (mode);
+ if (const0 == 0
+ && (op0 == IOR || op0 == XOR || op0 == PLUS))
+ op0 = UNKNOWN;
+ else if (const0 == 0 && op0 == AND)
+ op0 = SET;
+ else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
+ && op0 == AND)
+ op0 = UNKNOWN;
+
+ *pop0 = op0;
+
+ /* ??? Slightly redundant with the above mask, but not entirely.
+ Moving this above means we'd have to sign-extend the mode mask
+ for the final test. */
+ if (op0 != UNKNOWN && op0 != NEG)
+ *pconst0 = trunc_int_for_mode (const0, mode);
+
+ return 1;
+}
+
+/* A helper to simplify_shift_const_1 to determine the mode we can perform
+ the shift in. The original shift operation CODE is performed on OP in
+ ORIG_MODE. Return the wider mode MODE if we can perform the operation
+ in that mode. Return ORIG_MODE otherwise. We can also assume that the
+ result of the shift is subject to operation OUTER_CODE with operand
+ OUTER_CONST. */
+
+static scalar_int_mode
+try_widen_shift_mode (enum rtx_code code, rtx op, int count,
+ scalar_int_mode orig_mode, scalar_int_mode mode,
+ enum rtx_code outer_code, HOST_WIDE_INT outer_const)
+{
+ gcc_assert (GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (orig_mode));
+
+ /* In general we can't perform in wider mode for right shift and rotate. */
+ switch (code)
+ {
+ case ASHIFTRT:
+ /* We can still widen if the bits brought in from the left are identical
+ to the sign bit of ORIG_MODE. */
+ if (num_sign_bit_copies (op, mode)
+ > (unsigned) (GET_MODE_PRECISION (mode)
+ - GET_MODE_PRECISION (orig_mode)))
+ return mode;
+ return orig_mode;
+
+ case LSHIFTRT:
+ /* Similarly here but with zero bits. */
+ if (HWI_COMPUTABLE_MODE_P (mode)
+ && (nonzero_bits (op, mode) & ~GET_MODE_MASK (orig_mode)) == 0)
+ return mode;
+
+ /* We can also widen if the bits brought in will be masked off. This
+ operation is performed in ORIG_MODE. */
+ if (outer_code == AND)
+ {
+ int care_bits = low_bitmask_len (orig_mode, outer_const);
+
+ if (care_bits >= 0
+ && GET_MODE_PRECISION (orig_mode) - care_bits >= count)
+ return mode;
+ }
+ /* fall through */
+
+ case ROTATE:
+ return orig_mode;
+
+ case ROTATERT:
+ gcc_unreachable ();
+
+ default:
+ return mode;
+ }
+}
+
+/* Simplify a shift of VAROP by ORIG_COUNT bits. CODE says what kind
+ of shift. The result of the shift is RESULT_MODE. Return NULL_RTX
+ if we cannot simplify it. Otherwise, return a simplified value.
+
+ The shift is normally computed in the widest mode we find in VAROP, as
+ long as it isn't a different number of words than RESULT_MODE. Exceptions
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
+
+static rtx
+simplify_shift_const_1 (enum rtx_code code, machine_mode result_mode,
+ rtx varop, int orig_count)
+{
+ enum rtx_code orig_code = code;
+ rtx orig_varop = varop;
+ int count, log2;
+ machine_mode mode = result_mode;
+ machine_mode shift_mode;
+ scalar_int_mode tmode, inner_mode, int_mode, int_varop_mode, int_result_mode;
+ /* We form (outer_op (code varop count) (outer_const)). */
+ enum rtx_code outer_op = UNKNOWN;
+ HOST_WIDE_INT outer_const = 0;
+ int complement_p = 0;
+ rtx new_rtx, x;
+
+ /* Make sure and truncate the "natural" shift on the way in. We don't
+ want to do this inside the loop as it makes it more difficult to
+ combine shifts. */
+ if (SHIFT_COUNT_TRUNCATED)
+ orig_count &= GET_MODE_UNIT_BITSIZE (mode) - 1;
+
+ /* If we were given an invalid count, don't do anything except exactly
+ what was requested. */
+
+ if (orig_count < 0 || orig_count >= (int) GET_MODE_UNIT_PRECISION (mode))
+ return NULL_RTX;
+
+ count = orig_count;
+
+ /* Unless one of the branches of the `if' in this loop does a `continue',
+ we will `break' the loop after the `if'. */
+
+ while (count != 0)
+ {
+ /* If we have an operand of (clobber (const_int 0)), fail. */
+ if (GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
+ /* Convert ROTATERT to ROTATE. */
+ if (code == ROTATERT)
+ {
+ unsigned int bitsize = GET_MODE_UNIT_PRECISION (result_mode);
+ code = ROTATE;
+ count = bitsize - count;
+ }
+
+ shift_mode = result_mode;
+ if (shift_mode != mode)
+ {
+ /* We only change the modes of scalar shifts. */
+ int_mode = as_a <scalar_int_mode> (mode);
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+ shift_mode = try_widen_shift_mode (code, varop, count,
+ int_result_mode, int_mode,
+ outer_op, outer_const);
+ }
+
+ scalar_int_mode shift_unit_mode
+ = as_a <scalar_int_mode> (GET_MODE_INNER (shift_mode));
+
+ /* Handle cases where the count is greater than the size of the mode
+ minus 1. For ASHIFT, use the size minus one as the count (this can
+ occur when simplifying (lshiftrt (ashiftrt ..))). For rotates,
+ take the count modulo the size. For other shifts, the result is
+ zero.
+
+ Since these shifts are being produced by the compiler by combining
+ multiple operations, each of which are defined, we know what the
+ result is supposed to be. */
+
+ if (count > (GET_MODE_PRECISION (shift_unit_mode) - 1))
+ {
+ if (code == ASHIFTRT)
+ count = GET_MODE_PRECISION (shift_unit_mode) - 1;
+ else if (code == ROTATE || code == ROTATERT)
+ count %= GET_MODE_PRECISION (shift_unit_mode);
+ else
+ {
+ /* We can't simply return zero because there may be an
+ outer op. */
+ varop = const0_rtx;
+ count = 0;
+ break;
+ }
+ }
+
+ /* If we discovered we had to complement VAROP, leave. Making a NOT
+ here would cause an infinite loop. */
+ if (complement_p)
+ break;
+
+ if (shift_mode == shift_unit_mode)
+ {
+ /* An arithmetic right shift of a quantity known to be -1 or 0
+ is a no-op. */
+ if (code == ASHIFTRT
+ && (num_sign_bit_copies (varop, shift_unit_mode)
+ == GET_MODE_PRECISION (shift_unit_mode)))
+ {
+ count = 0;
+ break;
+ }
+
+ /* If we are doing an arithmetic right shift and discarding all but
+ the sign bit copies, this is equivalent to doing a shift by the
+ bitsize minus one. Convert it into that shift because it will
+ often allow other simplifications. */
+
+ if (code == ASHIFTRT
+ && (count + num_sign_bit_copies (varop, shift_unit_mode)
+ >= GET_MODE_PRECISION (shift_unit_mode)))
+ count = GET_MODE_PRECISION (shift_unit_mode) - 1;
+
+ /* We simplify the tests below and elsewhere by converting
+ ASHIFTRT to LSHIFTRT if we know the sign bit is clear.
+ `make_compound_operation' will convert it to an ASHIFTRT for
+ those machines (such as VAX) that don't have an LSHIFTRT. */
+ if (code == ASHIFTRT
+ && HWI_COMPUTABLE_MODE_P (shift_unit_mode)
+ && val_signbit_known_clear_p (shift_unit_mode,
+ nonzero_bits (varop,
+ shift_unit_mode)))
+ code = LSHIFTRT;
+
+ if (((code == LSHIFTRT
+ && HWI_COMPUTABLE_MODE_P (shift_unit_mode)
+ && !(nonzero_bits (varop, shift_unit_mode) >> count))
+ || (code == ASHIFT
+ && HWI_COMPUTABLE_MODE_P (shift_unit_mode)
+ && !((nonzero_bits (varop, shift_unit_mode) << count)
+ & GET_MODE_MASK (shift_unit_mode))))
+ && !side_effects_p (varop))
+ varop = const0_rtx;
+ }
+
+ switch (GET_CODE (varop))
+ {
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ case SIGN_EXTRACT:
+ case ZERO_EXTRACT:
+ new_rtx = expand_compound_operation (varop);
+ if (new_rtx != varop)
+ {
+ varop = new_rtx;
+ continue;
+ }
+ break;
+
+ case MEM:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_mode = as_a <scalar_int_mode> (mode);
+
+ /* If we have (xshiftrt (mem ...) C) and C is MODE_WIDTH
+ minus the width of a smaller mode, we can do this with a
+ SIGN_EXTEND or ZERO_EXTEND from the narrower memory location. */
+ if ((code == ASHIFTRT || code == LSHIFTRT)
+ && ! mode_dependent_address_p (XEXP (varop, 0),
+ MEM_ADDR_SPACE (varop))
+ && ! MEM_VOLATILE_P (varop)
+ && (int_mode_for_size (GET_MODE_BITSIZE (int_mode) - count, 1)
+ .exists (&tmode)))
+ {
+ new_rtx = adjust_address_nv (varop, tmode,
+ BYTES_BIG_ENDIAN ? 0
+ : count / BITS_PER_UNIT);
+
+ varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
+ : ZERO_EXTEND, int_mode, new_rtx);
+ count = 0;
+ continue;
+ }
+ break;
+
+ case SUBREG:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_mode = as_a <scalar_int_mode> (mode);
+ int_varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+
+ /* If VAROP is a SUBREG, strip it as long as the inner operand has
+ the same number of words as what we've seen so far. Then store
+ the widest mode in MODE. */
+ if (subreg_lowpart_p (varop)
+ && is_int_mode (GET_MODE (SUBREG_REG (varop)), &inner_mode)
+ && GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (int_varop_mode)
+ && (CEIL (GET_MODE_SIZE (inner_mode), UNITS_PER_WORD)
+ == CEIL (GET_MODE_SIZE (int_mode), UNITS_PER_WORD))
+ && GET_MODE_CLASS (int_varop_mode) == MODE_INT)
+ {
+ varop = SUBREG_REG (varop);
+ if (GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (int_mode))
+ mode = inner_mode;
+ continue;
+ }
+ break;
+
+ case MULT:
+ /* Some machines use MULT instead of ASHIFT because MULT
+ is cheaper. But it is still better on those machines to
+ merge two shifts into one. */
+ if (CONST_INT_P (XEXP (varop, 1))
+ && (log2 = exact_log2 (UINTVAL (XEXP (varop, 1)))) >= 0)
+ {
+ rtx log2_rtx = gen_int_shift_amount (GET_MODE (varop), log2);
+ varop = simplify_gen_binary (ASHIFT, GET_MODE (varop),
+ XEXP (varop, 0), log2_rtx);
+ continue;
+ }
+ break;
+
+ case UDIV:
+ /* Similar, for when divides are cheaper. */
+ if (CONST_INT_P (XEXP (varop, 1))
+ && (log2 = exact_log2 (UINTVAL (XEXP (varop, 1)))) >= 0)
+ {
+ rtx log2_rtx = gen_int_shift_amount (GET_MODE (varop), log2);
+ varop = simplify_gen_binary (LSHIFTRT, GET_MODE (varop),
+ XEXP (varop, 0), log2_rtx);
+ continue;
+ }
+ break;
+
+ case ASHIFTRT:
+ /* If we are extracting just the sign bit of an arithmetic
+ right shift, that shift is not needed. However, the sign
+ bit of a wider mode may be different from what would be
+ interpreted as the sign bit in a narrower mode, so, if
+ the result is narrower, don't discard the shift. */
+ if (code == LSHIFTRT
+ && count == (GET_MODE_UNIT_BITSIZE (result_mode) - 1)
+ && (GET_MODE_UNIT_BITSIZE (result_mode)
+ >= GET_MODE_UNIT_BITSIZE (GET_MODE (varop))))
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ /* fall through */
+
+ case LSHIFTRT:
+ case ASHIFT:
+ case ROTATE:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_mode = as_a <scalar_int_mode> (mode);
+ int_varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ /* Here we have two nested shifts. The result is usually the
+ AND of a new shift with a mask. We compute the result below. */
+ if (CONST_INT_P (XEXP (varop, 1))
+ && INTVAL (XEXP (varop, 1)) >= 0
+ && INTVAL (XEXP (varop, 1)) < GET_MODE_PRECISION (int_varop_mode)
+ && HWI_COMPUTABLE_MODE_P (int_result_mode)
+ && HWI_COMPUTABLE_MODE_P (int_mode))
+ {
+ enum rtx_code first_code = GET_CODE (varop);
+ unsigned int first_count = INTVAL (XEXP (varop, 1));
+ unsigned HOST_WIDE_INT mask;
+ rtx mask_rtx;
+
+ /* We have one common special case. We can't do any merging if
+ the inner code is an ASHIFTRT of a smaller mode. However, if
+ we have (ashift:M1 (subreg:M1 (ashiftrt:M2 FOO C1) 0) C2)
+ with C2 == GET_MODE_BITSIZE (M1) - GET_MODE_BITSIZE (M2),
+ we can convert it to
+ (ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0) C3) C2) C1).
+ This simplifies certain SIGN_EXTEND operations. */
+ if (code == ASHIFT && first_code == ASHIFTRT
+ && count == (GET_MODE_PRECISION (int_result_mode)
+ - GET_MODE_PRECISION (int_varop_mode)))
+ {
+ /* C3 has the low-order C1 bits zero. */
+
+ mask = GET_MODE_MASK (int_mode)
+ & ~((HOST_WIDE_INT_1U << first_count) - 1);
+
+ varop = simplify_and_const_int (NULL_RTX, int_result_mode,
+ XEXP (varop, 0), mask);
+ varop = simplify_shift_const (NULL_RTX, ASHIFT,
+ int_result_mode, varop, count);
+ count = first_count;
+ code = ASHIFTRT;
+ continue;
+ }
+
+ /* If this was (ashiftrt (ashift foo C1) C2) and FOO has more
+ than C1 high-order bits equal to the sign bit, we can convert
+ this to either an ASHIFT or an ASHIFTRT depending on the
+ two counts.
+
+ We cannot do this if VAROP's mode is not SHIFT_UNIT_MODE. */
+
+ if (code == ASHIFTRT && first_code == ASHIFT
+ && int_varop_mode == shift_unit_mode
+ && (num_sign_bit_copies (XEXP (varop, 0), shift_unit_mode)
+ > first_count))
+ {
+ varop = XEXP (varop, 0);
+ count -= first_count;
+ if (count < 0)
+ {
+ count = -count;
+ code = ASHIFT;
+ }
+
+ continue;
+ }
+
+ /* There are some cases we can't do. If CODE is ASHIFTRT,
+ we can only do this if FIRST_CODE is also ASHIFTRT.
+
+ We can't do the case when CODE is ROTATE and FIRST_CODE is
+ ASHIFTRT.
+
+ If the mode of this shift is not the mode of the outer shift,
+ we can't do this if either shift is a right shift or ROTATE.
+
+ Finally, we can't do any of these if the mode is too wide
+ unless the codes are the same.
+
+ Handle the case where the shift codes are the same
+ first. */
+
+ if (code == first_code)
+ {
+ if (int_varop_mode != int_result_mode
+ && (code == ASHIFTRT || code == LSHIFTRT
+ || code == ROTATE))
+ break;
+
+ count += first_count;
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ if (code == ASHIFTRT
+ || (code == ROTATE && first_code == ASHIFTRT)
+ || GET_MODE_PRECISION (int_mode) > HOST_BITS_PER_WIDE_INT
+ || (int_varop_mode != int_result_mode
+ && (first_code == ASHIFTRT || first_code == LSHIFTRT
+ || first_code == ROTATE
+ || code == ROTATE)))
+ break;
+
+ /* To compute the mask to apply after the shift, shift the
+ nonzero bits of the inner shift the same way the
+ outer shift will. */
+
+ mask_rtx = gen_int_mode (nonzero_bits (varop, int_varop_mode),
+ int_result_mode);
+ rtx count_rtx = gen_int_shift_amount (int_result_mode, count);
+ mask_rtx
+ = simplify_const_binary_operation (code, int_result_mode,
+ mask_rtx, count_rtx);
+
+ /* Give up if we can't compute an outer operation to use. */
+ if (mask_rtx == 0
+ || !CONST_INT_P (mask_rtx)
+ || ! merge_outer_ops (&outer_op, &outer_const, AND,
+ INTVAL (mask_rtx),
+ int_result_mode, &complement_p))
+ break;
+
+ /* If the shifts are in the same direction, we add the
+ counts. Otherwise, we subtract them. */
+ if ((code == ASHIFTRT || code == LSHIFTRT)
+ == (first_code == ASHIFTRT || first_code == LSHIFTRT))
+ count += first_count;
+ else
+ count -= first_count;
+
+ /* If COUNT is positive, the new shift is usually CODE,
+ except for the two exceptions below, in which case it is
+ FIRST_CODE. If the count is negative, FIRST_CODE should
+ always be used */
+ if (count > 0
+ && ((first_code == ROTATE && code == ASHIFT)
+ || (first_code == ASHIFTRT && code == LSHIFTRT)))
+ code = first_code;
+ else if (count < 0)
+ code = first_code, count = -count;
+
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ /* If we have (A << B << C) for any shift, we can convert this to
+ (A << C << B). This wins if A is a constant. Only try this if
+ B is not a constant. */
+
+ else if (GET_CODE (varop) == code
+ && CONST_INT_P (XEXP (varop, 0))
+ && !CONST_INT_P (XEXP (varop, 1)))
+ {
+ /* For ((unsigned) (cstULL >> count)) >> cst2 we have to make
+ sure the result will be masked. See PR70222. */
+ if (code == LSHIFTRT
+ && int_mode != int_result_mode
+ && !merge_outer_ops (&outer_op, &outer_const, AND,
+ GET_MODE_MASK (int_result_mode)
+ >> orig_count, int_result_mode,
+ &complement_p))
+ break;
+ /* For ((int) (cstLL >> count)) >> cst2 just give up. Queuing
+ up outer sign extension (often left and right shift) is
+ hardly more efficient than the original. See PR70429.
+ Similarly punt for rotates with different modes.
+ See PR97386. */
+ if ((code == ASHIFTRT || code == ROTATE)
+ && int_mode != int_result_mode)
+ break;
+
+ rtx count_rtx = gen_int_shift_amount (int_result_mode, count);
+ rtx new_rtx = simplify_const_binary_operation (code, int_mode,
+ XEXP (varop, 0),
+ count_rtx);
+ varop = gen_rtx_fmt_ee (code, int_mode, new_rtx, XEXP (varop, 1));
+ count = 0;
+ continue;
+ }
+ break;
+
+ case NOT:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+
+ /* Make this fit the case below. */
+ varop = gen_rtx_XOR (mode, XEXP (varop, 0), constm1_rtx);
+ continue;
+
+ case IOR:
+ case AND:
+ case XOR:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ /* If we have (xshiftrt (ior (plus X (const_int -1)) X) C)
+ with C the size of VAROP - 1 and the shift is logical if
+ STORE_FLAG_VALUE is 1 and arithmetic if STORE_FLAG_VALUE is -1,
+ we have an (le X 0) operation. If we have an arithmetic shift
+ and STORE_FLAG_VALUE is 1 or we have a logical shift with
+ STORE_FLAG_VALUE of -1, we have a (neg (le X 0)) operation. */
+
+ if (GET_CODE (varop) == IOR && GET_CODE (XEXP (varop, 0)) == PLUS
+ && XEXP (XEXP (varop, 0), 1) == constm1_rtx
+ && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == LSHIFTRT || code == ASHIFTRT)
+ && count == (GET_MODE_PRECISION (int_varop_mode) - 1)
+ && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
+ {
+ count = 0;
+ varop = gen_rtx_LE (int_varop_mode, XEXP (varop, 1),
+ const0_rtx);
+
+ if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
+ varop = gen_rtx_NEG (int_varop_mode, varop);
+
+ continue;
+ }
+
+ /* If we have (shift (logical)), move the logical to the outside
+ to allow it to possibly combine with another logical and the
+ shift to combine with another shift. This also canonicalizes to
+ what a ZERO_EXTRACT looks like. Also, some machines have
+ (and (shift)) insns. */
+
+ if (CONST_INT_P (XEXP (varop, 1))
+ /* We can't do this if we have (ashiftrt (xor)) and the
+ constant has its sign bit set in shift_unit_mode with
+ shift_unit_mode wider than result_mode. */
+ && !(code == ASHIFTRT && GET_CODE (varop) == XOR
+ && int_result_mode != shift_unit_mode
+ && trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+ shift_unit_mode) < 0)
+ && (new_rtx = simplify_const_binary_operation
+ (code, int_result_mode,
+ gen_int_mode (INTVAL (XEXP (varop, 1)), int_result_mode),
+ gen_int_shift_amount (int_result_mode, count))) != 0
+ && CONST_INT_P (new_rtx)
+ && merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
+ INTVAL (new_rtx), int_result_mode,
+ &complement_p))
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ /* If we can't do that, try to simplify the shift in each arm of the
+ logical expression, make a new logical expression, and apply
+ the inverse distributive law. This also can't be done for
+ (ashiftrt (xor)) where we've widened the shift and the constant
+ changes the sign bit. */
+ if (CONST_INT_P (XEXP (varop, 1))
+ && !(code == ASHIFTRT && GET_CODE (varop) == XOR
+ && int_result_mode != shift_unit_mode
+ && trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+ shift_unit_mode) < 0))
+ {
+ rtx lhs = simplify_shift_const (NULL_RTX, code, shift_unit_mode,
+ XEXP (varop, 0), count);
+ rtx rhs = simplify_shift_const (NULL_RTX, code, shift_unit_mode,
+ XEXP (varop, 1), count);
+
+ varop = simplify_gen_binary (GET_CODE (varop), shift_unit_mode,
+ lhs, rhs);
+ varop = apply_distributive_law (varop);
+
+ count = 0;
+ continue;
+ }
+ break;
+
+ case EQ:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ /* Convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
+ says that the sign bit can be tested, FOO has mode MODE, C is
+ GET_MODE_PRECISION (MODE) - 1, and FOO has only its low-order bit
+ that may be nonzero. */
+ if (code == LSHIFTRT
+ && XEXP (varop, 1) == const0_rtx
+ && GET_MODE (XEXP (varop, 0)) == int_result_mode
+ && count == (GET_MODE_PRECISION (int_result_mode) - 1)
+ && HWI_COMPUTABLE_MODE_P (int_result_mode)
+ && STORE_FLAG_VALUE == -1
+ && nonzero_bits (XEXP (varop, 0), int_result_mode) == 1
+ && merge_outer_ops (&outer_op, &outer_const, XOR, 1,
+ int_result_mode, &complement_p))
+ {
+ varop = XEXP (varop, 0);
+ count = 0;
+ continue;
+ }
+ break;
+
+ case NEG:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
+ than the number of bits in the mode is equivalent to A. */
+ if (code == LSHIFTRT
+ && count == (GET_MODE_PRECISION (int_result_mode) - 1)
+ && nonzero_bits (XEXP (varop, 0), int_result_mode) == 1)
+ {
+ varop = XEXP (varop, 0);
+ count = 0;
+ continue;
+ }
+
+ /* NEG commutes with ASHIFT since it is multiplication. Move the
+ NEG outside to allow shifts to combine. */
+ if (code == ASHIFT
+ && merge_outer_ops (&outer_op, &outer_const, NEG, 0,
+ int_result_mode, &complement_p))
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+ break;
+
+ case PLUS:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ /* (lshiftrt (plus A -1) C) where A is either 0 or 1 and C
+ is one less than the number of bits in the mode is
+ equivalent to (xor A 1). */
+ if (code == LSHIFTRT
+ && count == (GET_MODE_PRECISION (int_result_mode) - 1)
+ && XEXP (varop, 1) == constm1_rtx
+ && nonzero_bits (XEXP (varop, 0), int_result_mode) == 1
+ && merge_outer_ops (&outer_op, &outer_const, XOR, 1,
+ int_result_mode, &complement_p))
+ {
+ count = 0;
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ /* If we have (xshiftrt (plus FOO BAR) C), and the only bits
+ that might be nonzero in BAR are those being shifted out and those
+ bits are known zero in FOO, we can replace the PLUS with FOO.
+ Similarly in the other operand order. This code occurs when
+ we are computing the size of a variable-size array. */
+
+ if ((code == ASHIFTRT || code == LSHIFTRT)
+ && count < HOST_BITS_PER_WIDE_INT
+ && nonzero_bits (XEXP (varop, 1), int_result_mode) >> count == 0
+ && (nonzero_bits (XEXP (varop, 1), int_result_mode)
+ & nonzero_bits (XEXP (varop, 0), int_result_mode)) == 0)
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+ else if ((code == ASHIFTRT || code == LSHIFTRT)
+ && count < HOST_BITS_PER_WIDE_INT
+ && HWI_COMPUTABLE_MODE_P (int_result_mode)
+ && (nonzero_bits (XEXP (varop, 0), int_result_mode)
+ >> count) == 0
+ && (nonzero_bits (XEXP (varop, 0), int_result_mode)
+ & nonzero_bits (XEXP (varop, 1), int_result_mode)) == 0)
+ {
+ varop = XEXP (varop, 1);
+ continue;
+ }
+
+ /* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */
+ if (code == ASHIFT
+ && CONST_INT_P (XEXP (varop, 1))
+ && (new_rtx = simplify_const_binary_operation
+ (ASHIFT, int_result_mode,
+ gen_int_mode (INTVAL (XEXP (varop, 1)), int_result_mode),
+ gen_int_shift_amount (int_result_mode, count))) != 0
+ && CONST_INT_P (new_rtx)
+ && merge_outer_ops (&outer_op, &outer_const, PLUS,
+ INTVAL (new_rtx), int_result_mode,
+ &complement_p))
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ /* Check for 'PLUS signbit', which is the canonical form of 'XOR
+ signbit', and attempt to change the PLUS to an XOR and move it to
+ the outer operation as is done above in the AND/IOR/XOR case
+ leg for shift(logical). See details in logical handling above
+ for reasoning in doing so. */
+ if (code == LSHIFTRT
+ && CONST_INT_P (XEXP (varop, 1))
+ && mode_signbit_p (int_result_mode, XEXP (varop, 1))
+ && (new_rtx = simplify_const_binary_operation
+ (code, int_result_mode,
+ gen_int_mode (INTVAL (XEXP (varop, 1)), int_result_mode),
+ gen_int_shift_amount (int_result_mode, count))) != 0
+ && CONST_INT_P (new_rtx)
+ && merge_outer_ops (&outer_op, &outer_const, XOR,
+ INTVAL (new_rtx), int_result_mode,
+ &complement_p))
+ {
+ varop = XEXP (varop, 0);
+ continue;
+ }
+
+ break;
+
+ case MINUS:
+ /* The following rules apply only to scalars. */
+ if (shift_mode != shift_unit_mode)
+ break;
+ int_varop_mode = as_a <scalar_int_mode> (GET_MODE (varop));
+
+ /* If we have (xshiftrt (minus (ashiftrt X C)) X) C)
+ with C the size of VAROP - 1 and the shift is logical if
+ STORE_FLAG_VALUE is 1 and arithmetic if STORE_FLAG_VALUE is -1,
+ we have a (gt X 0) operation. If the shift is arithmetic with
+ STORE_FLAG_VALUE of 1 or logical with STORE_FLAG_VALUE == -1,
+ we have a (neg (gt X 0)) operation. */
+
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
+ && count == (GET_MODE_PRECISION (int_varop_mode) - 1)
+ && (code == LSHIFTRT || code == ASHIFTRT)
+ && CONST_INT_P (XEXP (XEXP (varop, 0), 1))
+ && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
+ && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
+ {
+ count = 0;
+ varop = gen_rtx_GT (int_varop_mode, XEXP (varop, 1),
+ const0_rtx);
+
+ if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
+ varop = gen_rtx_NEG (int_varop_mode, varop);
+
+ continue;
+ }
+ break;
+
+ case TRUNCATE:
+ /* Change (lshiftrt (truncate (lshiftrt))) to (truncate (lshiftrt))
+ if the truncate does not affect the value. */
+ if (code == LSHIFTRT
+ && GET_CODE (XEXP (varop, 0)) == LSHIFTRT
+ && CONST_INT_P (XEXP (XEXP (varop, 0), 1))
+ && (INTVAL (XEXP (XEXP (varop, 0), 1))
+ >= (GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (varop, 0)))
+ - GET_MODE_UNIT_PRECISION (GET_MODE (varop)))))
+ {
+ rtx varop_inner = XEXP (varop, 0);
+ int new_count = count + INTVAL (XEXP (varop_inner, 1));
+ rtx new_count_rtx = gen_int_shift_amount (GET_MODE (varop_inner),
+ new_count);
+ varop_inner = gen_rtx_LSHIFTRT (GET_MODE (varop_inner),
+ XEXP (varop_inner, 0),
+ new_count_rtx);
+ varop = gen_rtx_TRUNCATE (GET_MODE (varop), varop_inner);
+ count = 0;
+ continue;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ shift_mode = result_mode;
+ if (shift_mode != mode)
+ {
+ /* We only change the modes of scalar shifts. */
+ int_mode = as_a <scalar_int_mode> (mode);
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+ shift_mode = try_widen_shift_mode (code, varop, count, int_result_mode,
+ int_mode, outer_op, outer_const);
+ }
+
+ /* We have now finished analyzing the shift. The result should be
+ a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If
+ OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied
+ to the result of the shift. OUTER_CONST is the relevant constant,
+ but we must turn off all bits turned off in the shift. */
+
+ if (outer_op == UNKNOWN
+ && orig_code == code && orig_count == count
+ && varop == orig_varop
+ && shift_mode == GET_MODE (varop))
+ return NULL_RTX;
+
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (shift_mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
+ /* If we have an outer operation and we just made a shift, it is
+ possible that we could have simplified the shift were it not
+ for the outer operation. So try to do the simplification
+ recursively. */
+
+ if (outer_op != UNKNOWN)
+ x = simplify_shift_const_1 (code, shift_mode, varop, count);
+ else
+ x = NULL_RTX;
+
+ if (x == NULL_RTX)
+ x = simplify_gen_binary (code, shift_mode, varop,
+ gen_int_shift_amount (shift_mode, count));
+
+ /* If we were doing an LSHIFTRT in a wider mode than it was originally,
+ turn off all the bits that the shift would have turned off. */
+ if (orig_code == LSHIFTRT && result_mode != shift_mode)
+ /* We only change the modes of scalar shifts. */
+ x = simplify_and_const_int (NULL_RTX, as_a <scalar_int_mode> (shift_mode),
+ x, GET_MODE_MASK (result_mode) >> orig_count);
+
+ /* Do the remainder of the processing in RESULT_MODE. */
+ x = gen_lowpart_or_truncate (result_mode, x);
+
+ /* If COMPLEMENT_P is set, we have to complement X before doing the outer
+ operation. */
+ if (complement_p)
+ x = simplify_gen_unary (NOT, result_mode, x, result_mode);
+
+ if (outer_op != UNKNOWN)
+ {
+ int_result_mode = as_a <scalar_int_mode> (result_mode);
+
+ if (GET_RTX_CLASS (outer_op) != RTX_UNARY
+ && GET_MODE_PRECISION (int_result_mode) < HOST_BITS_PER_WIDE_INT)
+ outer_const = trunc_int_for_mode (outer_const, int_result_mode);
+
+ if (outer_op == AND)
+ x = simplify_and_const_int (NULL_RTX, int_result_mode, x, outer_const);
+ else if (outer_op == SET)
+ {
+ /* This means that we have determined that the result is
+ equivalent to a constant. This should be rare. */
+ if (!side_effects_p (x))
+ x = GEN_INT (outer_const);
+ }
+ else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
+ x = simplify_gen_unary (outer_op, int_result_mode, x, int_result_mode);
+ else
+ x = simplify_gen_binary (outer_op, int_result_mode, x,
+ GEN_INT (outer_const));
+ }
+
+ return x;
+}
+
+/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
+ The result of the shift is RESULT_MODE. If we cannot simplify it,
+ return X or, if it is NULL, synthesize the expression with
+ simplify_gen_binary. Otherwise, return a simplified value.
+
+ The shift is normally computed in the widest mode we find in VAROP, as
+ long as it isn't a different number of words than RESULT_MODE. Exceptions
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
+
+static rtx
+simplify_shift_const (rtx x, enum rtx_code code, machine_mode result_mode,
+ rtx varop, int count)
+{
+ rtx tem = simplify_shift_const_1 (code, result_mode, varop, count);
+ if (tem)
+ return tem;
+
+ if (!x)
+ x = simplify_gen_binary (code, GET_MODE (varop), varop,
+ gen_int_shift_amount (GET_MODE (varop), count));
+ if (GET_MODE (x) != result_mode)
+ x = gen_lowpart (result_mode, x);
+ return x;
+}
+
+
+/* A subroutine of recog_for_combine. See there for arguments and
+ return value. */
+
+static int
+recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
+{
+ rtx pat = *pnewpat;
+ rtx pat_without_clobbers;
+ int insn_code_number;
+ int num_clobbers_to_add = 0;
+ int i;
+ rtx notes = NULL_RTX;
+ rtx old_notes, old_pat;
+ int old_icode;
+
+ /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
+ we use to indicate that something didn't match. If we find such a
+ thing, force rejection. */
+ if (GET_CODE (pat) == PARALLEL)
+ for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER
+ && XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
+ return -1;
+
+ old_pat = PATTERN (insn);
+ old_notes = REG_NOTES (insn);
+ PATTERN (insn) = pat;
+ REG_NOTES (insn) = NULL_RTX;
+
+ insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (insn_code_number < 0)
+ fputs ("Failed to match this instruction:\n", dump_file);
+ else
+ fputs ("Successfully matched this instruction:\n", dump_file);
+ print_rtl_single (dump_file, pat);
+ }
+
+ /* If it isn't, there is the possibility that we previously had an insn
+ that clobbered some register as a side effect, but the combined
+ insn doesn't need to do that. So try once more without the clobbers
+ unless this represents an ASM insn. */
+
+ if (insn_code_number < 0 && ! check_asm_operands (pat)
+ && GET_CODE (pat) == PARALLEL)
+ {
+ int pos;
+
+ for (pos = 0, i = 0; i < XVECLEN (pat, 0); i++)
+ if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER)
+ {
+ if (i != pos)
+ SUBST (XVECEXP (pat, 0, pos), XVECEXP (pat, 0, i));
+ pos++;
+ }
+
+ SUBST_INT (XVECLEN (pat, 0), pos);
+
+ if (pos == 1)
+ pat = XVECEXP (pat, 0, 0);
+
+ PATTERN (insn) = pat;
+ insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (insn_code_number < 0)
+ fputs ("Failed to match this instruction:\n", dump_file);
+ else
+ fputs ("Successfully matched this instruction:\n", dump_file);
+ print_rtl_single (dump_file, pat);
+ }
+ }
+
+ pat_without_clobbers = pat;
+
+ PATTERN (insn) = old_pat;
+ REG_NOTES (insn) = old_notes;
+
+ /* Recognize all noop sets, these will be killed by followup pass. */
+ if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
+ insn_code_number = NOOP_MOVE_INSN_CODE, num_clobbers_to_add = 0;
+
+ /* If we had any clobbers to add, make a new pattern than contains
+ them. Then check to make sure that all of them are dead. */
+ if (num_clobbers_to_add)
+ {
+ rtx newpat = gen_rtx_PARALLEL (VOIDmode,
+ rtvec_alloc (GET_CODE (pat) == PARALLEL
+ ? (XVECLEN (pat, 0)
+ + num_clobbers_to_add)
+ : num_clobbers_to_add + 1));
+
+ if (GET_CODE (pat) == PARALLEL)
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ XVECEXP (newpat, 0, i) = XVECEXP (pat, 0, i);
+ else
+ XVECEXP (newpat, 0, 0) = pat;
+
+ add_clobbers (newpat, insn_code_number);
+
+ for (i = XVECLEN (newpat, 0) - num_clobbers_to_add;
+ i < XVECLEN (newpat, 0); i++)
+ {
+ if (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
+ && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
+ return -1;
+ if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
+ {
+ gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
+ notes = alloc_reg_note (REG_UNUSED,
+ XEXP (XVECEXP (newpat, 0, i), 0), notes);
+ }
+ }
+ pat = newpat;
+ }
+
+ if (insn_code_number >= 0
+ && insn_code_number != NOOP_MOVE_INSN_CODE)
+ {
+ old_pat = PATTERN (insn);
+ old_notes = REG_NOTES (insn);
+ old_icode = INSN_CODE (insn);
+ PATTERN (insn) = pat;
+ REG_NOTES (insn) = notes;
+ INSN_CODE (insn) = insn_code_number;
+
+ /* Allow targets to reject combined insn. */
+ if (!targetm.legitimate_combined_insn (insn))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fputs ("Instruction not appropriate for target.",
+ dump_file);
+
+ /* Callers expect recog_for_combine to strip
+ clobbers from the pattern on failure. */
+ pat = pat_without_clobbers;
+ notes = NULL_RTX;
+
+ insn_code_number = -1;
+ }
+
+ PATTERN (insn) = old_pat;
+ REG_NOTES (insn) = old_notes;
+ INSN_CODE (insn) = old_icode;
+ }
+
+ *pnewpat = pat;
+ *pnotes = notes;
+
+ return insn_code_number;
+}
+
+/* Change every ZERO_EXTRACT and ZERO_EXTEND of a SUBREG that can be
+ expressed as an AND and maybe an LSHIFTRT, to that formulation.
+ Return whether anything was so changed. */
+
+static bool
+change_zero_ext (rtx pat)
+{
+ bool changed = false;
+ rtx *src = &SET_SRC (pat);
+
+ subrtx_ptr_iterator::array_type array;
+ FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
+ {
+ rtx x = **iter;
+ scalar_int_mode mode, inner_mode;
+ if (!is_a <scalar_int_mode> (GET_MODE (x), &mode))
+ continue;
+ int size;
+
+ if (GET_CODE (x) == ZERO_EXTRACT
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (x, 2))
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)), &inner_mode)
+ && GET_MODE_PRECISION (inner_mode) <= GET_MODE_PRECISION (mode))
+ {
+ size = INTVAL (XEXP (x, 1));
+
+ int start = INTVAL (XEXP (x, 2));
+ if (BITS_BIG_ENDIAN)
+ start = GET_MODE_PRECISION (inner_mode) - size - start;
+
+ if (start != 0)
+ x = gen_rtx_LSHIFTRT (inner_mode, XEXP (x, 0),
+ gen_int_shift_amount (inner_mode, start));
+ else
+ x = XEXP (x, 0);
+
+ if (mode != inner_mode)
+ {
+ if (REG_P (x) && HARD_REGISTER_P (x)
+ && !can_change_dest_mode (x, 0, mode))
+ continue;
+
+ x = gen_lowpart_SUBREG (mode, x);
+ }
+ }
+ else if (GET_CODE (x) == ZERO_EXTEND
+ && GET_CODE (XEXP (x, 0)) == SUBREG
+ && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (XEXP (x, 0))))
+ && !paradoxical_subreg_p (XEXP (x, 0))
+ && subreg_lowpart_p (XEXP (x, 0)))
+ {
+ inner_mode = as_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)));
+ size = GET_MODE_PRECISION (inner_mode);
+ x = SUBREG_REG (XEXP (x, 0));
+ if (GET_MODE (x) != mode)
+ {
+ if (REG_P (x) && HARD_REGISTER_P (x)
+ && !can_change_dest_mode (x, 0, mode))
+ continue;
+
+ x = gen_lowpart_SUBREG (mode, x);
+ }
+ }
+ else if (GET_CODE (x) == ZERO_EXTEND
+ && REG_P (XEXP (x, 0))
+ && HARD_REGISTER_P (XEXP (x, 0))
+ && can_change_dest_mode (XEXP (x, 0), 0, mode))
+ {
+ inner_mode = as_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)));
+ size = GET_MODE_PRECISION (inner_mode);
+ x = gen_rtx_REG (mode, REGNO (XEXP (x, 0)));
+ }
+ else
+ continue;
+
+ if (!(GET_CODE (x) == LSHIFTRT
+ && CONST_INT_P (XEXP (x, 1))
+ && size + INTVAL (XEXP (x, 1)) == GET_MODE_PRECISION (mode)))
+ {
+ wide_int mask = wi::mask (size, false, GET_MODE_PRECISION (mode));
+ x = gen_rtx_AND (mode, x, immed_wide_int_const (mask, mode));
+ }
+
+ SUBST (**iter, x);
+ changed = true;
+ }
+
+ if (changed)
+ FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
+ maybe_swap_commutative_operands (**iter);
+
+ rtx *dst = &SET_DEST (pat);
+ scalar_int_mode mode;
+ if (GET_CODE (*dst) == ZERO_EXTRACT
+ && REG_P (XEXP (*dst, 0))
+ && is_a <scalar_int_mode> (GET_MODE (XEXP (*dst, 0)), &mode)
+ && CONST_INT_P (XEXP (*dst, 1))
+ && CONST_INT_P (XEXP (*dst, 2)))
+ {
+ rtx reg = XEXP (*dst, 0);
+ int width = INTVAL (XEXP (*dst, 1));
+ int offset = INTVAL (XEXP (*dst, 2));
+ int reg_width = GET_MODE_PRECISION (mode);
+ if (BITS_BIG_ENDIAN)
+ offset = reg_width - width - offset;
+
+ rtx x, y, z, w;
+ wide_int mask = wi::shifted_mask (offset, width, true, reg_width);
+ wide_int mask2 = wi::shifted_mask (offset, width, false, reg_width);
+ x = gen_rtx_AND (mode, reg, immed_wide_int_const (mask, mode));
+ if (offset)
+ y = gen_rtx_ASHIFT (mode, SET_SRC (pat), GEN_INT (offset));
+ else
+ y = SET_SRC (pat);
+ z = gen_rtx_AND (mode, y, immed_wide_int_const (mask2, mode));
+ w = gen_rtx_IOR (mode, x, z);
+ SUBST (SET_DEST (pat), reg);
+ SUBST (SET_SRC (pat), w);
+
+ changed = true;
+ }
+
+ return changed;
+}
+
+/* Like recog, but we receive the address of a pointer to a new pattern.
+ We try to match the rtx that the pointer points to.
+ If that fails, we may try to modify or replace the pattern,
+ storing the replacement into the same pointer object.
+
+ Modifications include deletion or addition of CLOBBERs. If the
+ instruction will still not match, we change ZERO_EXTEND and ZERO_EXTRACT
+ to the equivalent AND and perhaps LSHIFTRT patterns, and try with that
+ (and undo if that fails).
+
+ PNOTES is a pointer to a location where any REG_UNUSED notes added for
+ the CLOBBERs are placed.
+
+ The value is the final insn code from the pattern ultimately matched,
+ or -1. */
+
+static int
+recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
+{
+ rtx pat = *pnewpat;
+ int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
+ if (insn_code_number >= 0 || check_asm_operands (pat))
+ return insn_code_number;
+
+ void *marker = get_undo_marker ();
+ bool changed = false;
+
+ if (GET_CODE (pat) == SET)
+ {
+ /* For an unrecognized single set of a constant, try placing it in
+ the constant pool, if this function already uses one. */
+ rtx src = SET_SRC (pat);
+ if (CONSTANT_P (src)
+ && !CONST_INT_P (src)
+ && crtl->uses_const_pool)
+ {
+ machine_mode mode = GET_MODE (src);
+ if (mode == VOIDmode)
+ mode = GET_MODE (SET_DEST (pat));
+ src = force_const_mem (mode, src);
+ if (src)
+ {
+ SUBST (SET_SRC (pat), src);
+ changed = true;
+ }
+ }
+ else
+ changed = change_zero_ext (pat);
+ }
+ else if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx set = XVECEXP (pat, 0, i);
+ if (GET_CODE (set) == SET)
+ changed |= change_zero_ext (set);
+ }
+ }
+
+ if (changed)
+ {
+ insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
+
+ if (insn_code_number < 0)
+ undo_to_marker (marker);
+ }
+
+ return insn_code_number;
+}
+
+/* Like gen_lowpart_general but for use by combine. In combine it
+ is not possible to create any new pseudoregs. However, it is
+ safe to create invalid memory addresses, because combine will
+ try to recognize them and all they will do is make the combine
+ attempt fail.
+
+ If for some reason this cannot do its job, an rtx
+ (clobber (const_int 0)) is returned.
+ An insn containing that will not be recognized. */
+
+static rtx
+gen_lowpart_for_combine (machine_mode omode, rtx x)
+{
+ machine_mode imode = GET_MODE (x);
+ rtx result;
+
+ if (omode == imode)
+ return x;
+
+ /* We can only support MODE being wider than a word if X is a
+ constant integer or has a mode the same size. */
+ if (maybe_gt (GET_MODE_SIZE (omode), UNITS_PER_WORD)
+ && ! (CONST_SCALAR_INT_P (x)
+ || known_eq (GET_MODE_SIZE (imode), GET_MODE_SIZE (omode))))
+ goto fail;
+
+ /* X might be a paradoxical (subreg (mem)). In that case, gen_lowpart
+ won't know what to do. So we will strip off the SUBREG here and
+ process normally. */
+ if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
+ {
+ x = SUBREG_REG (x);
+
+ /* For use in case we fall down into the address adjustments
+ further below, we need to adjust the known mode and size of
+ x; imode and isize, since we just adjusted x. */
+ imode = GET_MODE (x);
+
+ if (imode == omode)
+ return x;
+ }
+
+ result = gen_lowpart_common (omode, x);
+
+ if (result)
+ return result;
+
+ if (MEM_P (x))
+ {
+ /* Refuse to work on a volatile memory ref or one with a mode-dependent
+ address. */
+ if (MEM_VOLATILE_P (x)
+ || mode_dependent_address_p (XEXP (x, 0), MEM_ADDR_SPACE (x)))
+ goto fail;
+
+ /* If we want to refer to something bigger than the original memref,
+ generate a paradoxical subreg instead. That will force a reload
+ of the original memref X. */
+ if (paradoxical_subreg_p (omode, imode))
+ return gen_rtx_SUBREG (omode, x, 0);
+
+ poly_int64 offset = byte_lowpart_offset (omode, imode);
+ return adjust_address_nv (x, omode, offset);
+ }
+
+ /* If X is a comparison operator, rewrite it in a new mode. This
+ probably won't match, but may allow further simplifications. */
+ else if (COMPARISON_P (x)
+ && SCALAR_INT_MODE_P (imode)
+ && SCALAR_INT_MODE_P (omode))
+ return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
+
+ /* If we couldn't simplify X any other way, just enclose it in a
+ SUBREG. Normally, this SUBREG won't match, but some patterns may
+ include an explicit SUBREG or we may simplify it further in combine. */
+ else
+ {
+ rtx res;
+
+ if (imode == VOIDmode)
+ {
+ imode = int_mode_for_mode (omode).require ();
+ x = gen_lowpart_common (imode, x);
+ if (x == NULL)
+ goto fail;
+ }
+ res = lowpart_subreg (omode, x, imode);
+ if (res)
+ return res;
+ }
+
+ fail:
+ return gen_rtx_CLOBBER (omode, const0_rtx);
+}
+
+/* Try to simplify a comparison between OP0 and a constant OP1,
+ where CODE is the comparison code that will be tested, into a
+ (CODE OP0 const0_rtx) form.
+
+ The result is a possibly different comparison code to use.
+ *POP1 may be updated. */
+
+static enum rtx_code
+simplify_compare_const (enum rtx_code code, machine_mode mode,
+ rtx op0, rtx *pop1)
+{
+ scalar_int_mode int_mode;
+ HOST_WIDE_INT const_op = INTVAL (*pop1);
+
+ /* Get the constant we are comparing against and turn off all bits
+ not on in our mode. */
+ if (mode != VOIDmode)
+ const_op = trunc_int_for_mode (const_op, mode);
+
+ /* If we are comparing against a constant power of two and the value
+ being compared can only have that single bit nonzero (e.g., it was
+ `and'ed with that bit), we can replace this with a comparison
+ with zero. */
+ if (const_op
+ && (code == EQ || code == NE || code == GE || code == GEU
+ || code == LT || code == LTU)
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && pow2p_hwi (const_op & GET_MODE_MASK (int_mode))
+ && (nonzero_bits (op0, int_mode)
+ == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (int_mode))))
+ {
+ code = (code == EQ || code == GE || code == GEU ? NE : EQ);
+ const_op = 0;
+ }
+
+ /* Similarly, if we are comparing a value known to be either -1 or
+ 0 with -1, change it to the opposite comparison against zero. */
+ if (const_op == -1
+ && (code == EQ || code == NE || code == GT || code == LE
+ || code == GEU || code == LTU)
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && num_sign_bit_copies (op0, int_mode) == GET_MODE_PRECISION (int_mode))
+ {
+ code = (code == EQ || code == LE || code == GEU ? NE : EQ);
+ const_op = 0;
+ }
+
+ /* Do some canonicalizations based on the comparison code. We prefer
+ comparisons against zero and then prefer equality comparisons.
+ If we can reduce the size of a constant, we will do that too. */
+ switch (code)
+ {
+ case LT:
+ /* < C is equivalent to <= (C - 1) */
+ if (const_op > 0)
+ {
+ const_op -= 1;
+ code = LE;
+ /* ... fall through to LE case below. */
+ gcc_fallthrough ();
+ }
+ else
+ break;
+
+ case LE:
+ /* <= C is equivalent to < (C + 1); we do this for C < 0 */
+ if (const_op < 0)
+ {
+ const_op += 1;
+ code = LT;
+ }
+
+ /* If we are doing a <= 0 comparison on a value known to have
+ a zero sign bit, we can replace this with == 0. */
+ else if (const_op == 0
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, int_mode)
+ & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
+ == 0)
+ code = EQ;
+ break;
+
+ case GE:
+ /* >= C is equivalent to > (C - 1). */
+ if (const_op > 0)
+ {
+ const_op -= 1;
+ code = GT;
+ /* ... fall through to GT below. */
+ gcc_fallthrough ();
+ }
+ else
+ break;
+
+ case GT:
+ /* > C is equivalent to >= (C + 1); we do this for C < 0. */
+ if (const_op < 0)
+ {
+ const_op += 1;
+ code = GE;
+ }
+
+ /* If we are doing a > 0 comparison on a value known to have
+ a zero sign bit, we can replace this with != 0. */
+ else if (const_op == 0
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, int_mode)
+ & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
+ == 0)
+ code = NE;
+ break;
+
+ case LTU:
+ /* < C is equivalent to <= (C - 1). */
+ if (const_op > 0)
+ {
+ const_op -= 1;
+ code = LEU;
+ /* ... fall through ... */
+ gcc_fallthrough ();
+ }
+ /* (unsigned) < 0x80000000 is equivalent to >= 0. */
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
+ {
+ const_op = 0;
+ code = GE;
+ break;
+ }
+ else
+ break;
+
+ case LEU:
+ /* unsigned <= 0 is equivalent to == 0 */
+ if (const_op == 0)
+ code = EQ;
+ /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == ((HOST_WIDE_INT_1U
+ << (GET_MODE_PRECISION (int_mode) - 1)) - 1)))
+ {
+ const_op = 0;
+ code = GE;
+ }
+ break;
+
+ case GEU:
+ /* >= C is equivalent to > (C - 1). */
+ if (const_op > 1)
+ {
+ const_op -= 1;
+ code = GTU;
+ /* ... fall through ... */
+ gcc_fallthrough ();
+ }
+
+ /* (unsigned) >= 0x80000000 is equivalent to < 0. */
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
+ {
+ const_op = 0;
+ code = LT;
+ break;
+ }
+ else
+ break;
+
+ case GTU:
+ /* unsigned > 0 is equivalent to != 0 */
+ if (const_op == 0)
+ code = NE;
+ /* (unsigned) > 0x7fffffff is equivalent to < 0. */
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == (HOST_WIDE_INT_1U
+ << (GET_MODE_PRECISION (int_mode) - 1)) - 1))
+ {
+ const_op = 0;
+ code = LT;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ *pop1 = GEN_INT (const_op);
+ return code;
+}
+
+/* Simplify a comparison between *POP0 and *POP1 where CODE is the
+ comparison code that will be tested.
+
+ The result is a possibly different comparison code to use. *POP0 and
+ *POP1 may be updated.
+
+ It is possible that we might detect that a comparison is either always
+ true or always false. However, we do not perform general constant
+ folding in combine, so this knowledge isn't useful. Such tautologies
+ should have been detected earlier. Hence we ignore all such cases. */
+
+static enum rtx_code
+simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
+{
+ rtx op0 = *pop0;
+ rtx op1 = *pop1;
+ rtx tem, tem1;
+ int i;
+ scalar_int_mode mode, inner_mode, tmode;
+ opt_scalar_int_mode tmode_iter;
+
+ /* Try a few ways of applying the same transformation to both operands. */
+ while (1)
+ {
+ /* The test below this one won't handle SIGN_EXTENDs on these machines,
+ so check specially. */
+ if (!WORD_REGISTER_OPERATIONS
+ && code != GTU && code != GEU && code != LTU && code != LEU
+ && GET_CODE (op0) == ASHIFTRT && GET_CODE (op1) == ASHIFTRT
+ && GET_CODE (XEXP (op0, 0)) == ASHIFT
+ && GET_CODE (XEXP (op1, 0)) == ASHIFT
+ && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SUBREG
+ && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SUBREG
+ && is_a <scalar_int_mode> (GET_MODE (op0), &mode)
+ && (is_a <scalar_int_mode>
+ (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0))), &inner_mode))
+ && inner_mode == GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0)))
+ && CONST_INT_P (XEXP (op0, 1))
+ && XEXP (op0, 1) == XEXP (op1, 1)
+ && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
+ && XEXP (op0, 1) == XEXP (XEXP (op1, 0), 1)
+ && (INTVAL (XEXP (op0, 1))
+ == (GET_MODE_PRECISION (mode)
+ - GET_MODE_PRECISION (inner_mode))))
+ {
+ op0 = SUBREG_REG (XEXP (XEXP (op0, 0), 0));
+ op1 = SUBREG_REG (XEXP (XEXP (op1, 0), 0));
+ }
+
+ /* If both operands are the same constant shift, see if we can ignore the
+ shift. We can if the shift is a rotate or if the bits shifted out of
+ this shift are known to be zero for both inputs and if the type of
+ comparison is compatible with the shift. */
+ if (GET_CODE (op0) == GET_CODE (op1)
+ && HWI_COMPUTABLE_MODE_P (GET_MODE (op0))
+ && ((GET_CODE (op0) == ROTATE && (code == NE || code == EQ))
+ || ((GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFT)
+ && (code != GT && code != LT && code != GE && code != LE))
+ || (GET_CODE (op0) == ASHIFTRT
+ && (code != GTU && code != LTU
+ && code != GEU && code != LEU)))
+ && CONST_INT_P (XEXP (op0, 1))
+ && INTVAL (XEXP (op0, 1)) >= 0
+ && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
+ && XEXP (op0, 1) == XEXP (op1, 1))
+ {
+ machine_mode mode = GET_MODE (op0);
+ unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+ int shift_count = INTVAL (XEXP (op0, 1));
+
+ if (GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFTRT)
+ mask &= (mask >> shift_count) << shift_count;
+ else if (GET_CODE (op0) == ASHIFT)
+ mask = (mask & (mask << shift_count)) >> shift_count;
+
+ if ((nonzero_bits (XEXP (op0, 0), mode) & ~mask) == 0
+ && (nonzero_bits (XEXP (op1, 0), mode) & ~mask) == 0)
+ op0 = XEXP (op0, 0), op1 = XEXP (op1, 0);
+ else
+ break;
+ }
+
+ /* If both operands are AND's of a paradoxical SUBREG by constant, the
+ SUBREGs are of the same mode, and, in both cases, the AND would
+ be redundant if the comparison was done in the narrower mode,
+ do the comparison in the narrower mode (e.g., we are AND'ing with 1
+ and the operand's possibly nonzero bits are 0xffffff01; in that case
+ if we only care about QImode, we don't need the AND). This case
+ occurs if the output mode of an scc insn is not SImode and
+ STORE_FLAG_VALUE == 1 (e.g., the 386).
+
+ Similarly, check for a case where the AND's are ZERO_EXTEND
+ operations from some narrower mode even though a SUBREG is not
+ present. */
+
+ else if (GET_CODE (op0) == AND && GET_CODE (op1) == AND
+ && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (XEXP (op1, 1)))
+ {
+ rtx inner_op0 = XEXP (op0, 0);
+ rtx inner_op1 = XEXP (op1, 0);
+ HOST_WIDE_INT c0 = INTVAL (XEXP (op0, 1));
+ HOST_WIDE_INT c1 = INTVAL (XEXP (op1, 1));
+ int changed = 0;
+
+ if (paradoxical_subreg_p (inner_op0)
+ && GET_CODE (inner_op1) == SUBREG
+ && HWI_COMPUTABLE_MODE_P (GET_MODE (SUBREG_REG (inner_op0)))
+ && (GET_MODE (SUBREG_REG (inner_op0))
+ == GET_MODE (SUBREG_REG (inner_op1)))
+ && ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
+ GET_MODE (SUBREG_REG (inner_op0)))) == 0
+ && ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
+ GET_MODE (SUBREG_REG (inner_op1)))) == 0)
+ {
+ op0 = SUBREG_REG (inner_op0);
+ op1 = SUBREG_REG (inner_op1);
+
+ /* The resulting comparison is always unsigned since we masked
+ off the original sign bit. */
+ code = unsigned_condition (code);
+
+ changed = 1;
+ }
+
+ else if (c0 == c1)
+ FOR_EACH_MODE_UNTIL (tmode,
+ as_a <scalar_int_mode> (GET_MODE (op0)))
+ if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode))
+ {
+ op0 = gen_lowpart_or_truncate (tmode, inner_op0);
+ op1 = gen_lowpart_or_truncate (tmode, inner_op1);
+ code = unsigned_condition (code);
+ changed = 1;
+ break;
+ }
+
+ if (! changed)
+ break;
+ }
+
+ /* If both operands are NOT, we can strip off the outer operation
+ and adjust the comparison code for swapped operands; similarly for
+ NEG, except that this must be an equality comparison. */
+ else if ((GET_CODE (op0) == NOT && GET_CODE (op1) == NOT)
+ || (GET_CODE (op0) == NEG && GET_CODE (op1) == NEG
+ && (code == EQ || code == NE)))
+ op0 = XEXP (op0, 0), op1 = XEXP (op1, 0), code = swap_condition (code);
+
+ else
+ break;
+ }
+
+ /* If the first operand is a constant, swap the operands and adjust the
+ comparison code appropriately, but don't do this if the second operand
+ is already a constant integer. */
+ if (swap_commutative_operands_p (op0, op1))
+ {
+ std::swap (op0, op1);
+ code = swap_condition (code);
+ }
+
+ /* We now enter a loop during which we will try to simplify the comparison.
+ For the most part, we only are concerned with comparisons with zero,
+ but some things may really be comparisons with zero but not start
+ out looking that way. */
+
+ while (CONST_INT_P (op1))
+ {
+ machine_mode raw_mode = GET_MODE (op0);
+ scalar_int_mode int_mode;
+ int equality_comparison_p;
+ int sign_bit_comparison_p;
+ int unsigned_comparison_p;
+ HOST_WIDE_INT const_op;
+
+ /* We only want to handle integral modes. This catches VOIDmode,
+ CCmode, and the floating-point modes. An exception is that we
+ can handle VOIDmode if OP0 is a COMPARE or a comparison
+ operation. */
+
+ if (GET_MODE_CLASS (raw_mode) != MODE_INT
+ && ! (raw_mode == VOIDmode
+ && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
+ break;
+
+ /* Try to simplify the compare to constant, possibly changing the
+ comparison op, and/or changing op1 to zero. */
+ code = simplify_compare_const (code, raw_mode, op0, &op1);
+ const_op = INTVAL (op1);
+
+ /* Compute some predicates to simplify code below. */
+
+ equality_comparison_p = (code == EQ || code == NE);
+ sign_bit_comparison_p = ((code == LT || code == GE) && const_op == 0);
+ unsigned_comparison_p = (code == LTU || code == LEU || code == GTU
+ || code == GEU);
+
+ /* If this is a sign bit comparison and we can do arithmetic in
+ MODE, say that we will only be needing the sign bit of OP0. */
+ if (sign_bit_comparison_p
+ && is_a <scalar_int_mode> (raw_mode, &int_mode)
+ && HWI_COMPUTABLE_MODE_P (int_mode))
+ op0 = force_to_mode (op0, int_mode,
+ HOST_WIDE_INT_1U
+ << (GET_MODE_PRECISION (int_mode) - 1),
+ 0);
+
+ if (COMPARISON_P (op0))
+ {
+ /* We can't do anything if OP0 is a condition code value, rather
+ than an actual data value. */
+ if (const_op != 0
+ || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+ break;
+
+ /* Get the two operands being compared. */
+ if (GET_CODE (XEXP (op0, 0)) == COMPARE)
+ tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
+ else
+ tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
+
+ /* Check for the cases where we simply want the result of the
+ earlier test or the opposite of that result. */
+ if (code == NE || code == EQ
+ || (val_signbit_known_set_p (raw_mode, STORE_FLAG_VALUE)
+ && (code == LT || code == GE)))
+ {
+ enum rtx_code new_code;
+ if (code == LT || code == NE)
+ new_code = GET_CODE (op0);
+ else
+ new_code = reversed_comparison_code (op0, NULL);
+
+ if (new_code != UNKNOWN)
+ {
+ code = new_code;
+ op0 = tem;
+ op1 = tem1;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (raw_mode == VOIDmode)
+ break;
+ scalar_int_mode mode = as_a <scalar_int_mode> (raw_mode);
+
+ /* Now try cases based on the opcode of OP0. If none of the cases
+ does a "continue", we exit this loop immediately after the
+ switch. */
+
+ unsigned int mode_width = GET_MODE_PRECISION (mode);
+ unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+ switch (GET_CODE (op0))
+ {
+ case ZERO_EXTRACT:
+ /* If we are extracting a single bit from a variable position in
+ a constant that has only a single bit set and are comparing it
+ with zero, we can convert this into an equality comparison
+ between the position and the location of the single bit. */
+ /* Except we can't if SHIFT_COUNT_TRUNCATED is set, since we might
+ have already reduced the shift count modulo the word size. */
+ if (!SHIFT_COUNT_TRUNCATED
+ && CONST_INT_P (XEXP (op0, 0))
+ && XEXP (op0, 1) == const1_rtx
+ && equality_comparison_p && const_op == 0
+ && (i = exact_log2 (UINTVAL (XEXP (op0, 0)))) >= 0)
+ {
+ if (BITS_BIG_ENDIAN)
+ i = BITS_PER_WORD - 1 - i;
+
+ op0 = XEXP (op0, 2);
+ op1 = GEN_INT (i);
+ const_op = i;
+
+ /* Result is nonzero iff shift count is equal to I. */
+ code = reverse_condition (code);
+ continue;
+ }
+
+ /* fall through */
+
+ case SIGN_EXTRACT:
+ tem = expand_compound_operation (op0);
+ if (tem != op0)
+ {
+ op0 = tem;
+ continue;
+ }
+ break;
+
+ case NOT:
+ /* If testing for equality, we can take the NOT of the constant. */
+ if (equality_comparison_p
+ && (tem = simplify_unary_operation (NOT, mode, op1, mode)) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ /* If just looking at the sign bit, reverse the sense of the
+ comparison. */
+ if (sign_bit_comparison_p)
+ {
+ op0 = XEXP (op0, 0);
+ code = (code == GE ? LT : GE);
+ continue;
+ }
+ break;
+
+ case NEG:
+ /* If testing for equality, we can take the NEG of the constant. */
+ if (equality_comparison_p
+ && (tem = simplify_unary_operation (NEG, mode, op1, mode)) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ /* The remaining cases only apply to comparisons with zero. */
+ if (const_op != 0)
+ break;
+
+ /* When X is ABS or is known positive,
+ (neg X) is < 0 if and only if X != 0. */
+
+ if (sign_bit_comparison_p
+ && (GET_CODE (XEXP (op0, 0)) == ABS
+ || (mode_width <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (op0, 0), mode)
+ & (HOST_WIDE_INT_1U << (mode_width - 1)))
+ == 0)))
+ {
+ op0 = XEXP (op0, 0);
+ code = (code == LT ? NE : EQ);
+ continue;
+ }
+
+ /* If we have NEG of something whose two high-order bits are the
+ same, we know that "(-a) < 0" is equivalent to "a > 0". */
+ if (num_sign_bit_copies (op0, mode) >= 2)
+ {
+ op0 = XEXP (op0, 0);
+ code = swap_condition (code);
+ continue;
+ }
+ break;
+
+ case ROTATE:
+ /* If we are testing equality and our count is a constant, we
+ can perform the inverse operation on our RHS. */
+ if (equality_comparison_p && CONST_INT_P (XEXP (op0, 1))
+ && (tem = simplify_binary_operation (ROTATERT, mode,
+ op1, XEXP (op0, 1))) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ /* If we are doing a < 0 or >= 0 comparison, it means we are testing
+ a particular bit. Convert it to an AND of a constant of that
+ bit. This will be converted into a ZERO_EXTRACT. */
+ if (const_op == 0 && sign_bit_comparison_p
+ && CONST_INT_P (XEXP (op0, 1))
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && UINTVAL (XEXP (op0, 1)) < mode_width)
+ {
+ op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
+ (HOST_WIDE_INT_1U
+ << (mode_width - 1
+ - INTVAL (XEXP (op0, 1)))));
+ code = (code == LT ? NE : EQ);
+ continue;
+ }
+
+ /* Fall through. */
+
+ case ABS:
+ /* ABS is ignorable inside an equality comparison with zero. */
+ if (const_op == 0 && equality_comparison_p)
+ {
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+ break;
+
+ case SIGN_EXTEND:
+ /* Can simplify (compare (zero/sign_extend FOO) CONST) to
+ (compare FOO CONST) if CONST fits in FOO's mode and we
+ are either testing inequality or have an unsigned
+ comparison with ZERO_EXTEND or a signed comparison with
+ SIGN_EXTEND. But don't do it if we don't have a compare
+ insn of the given mode, since we'd have to revert it
+ later on, and then we wouldn't know whether to sign- or
+ zero-extend. */
+ if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
+ && ! unsigned_comparison_p
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && trunc_int_for_mode (const_op, mode) == const_op
+ && have_insn_for (COMPARE, mode))
+ {
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+ break;
+
+ case SUBREG:
+ /* Check for the case where we are comparing A - C1 with C2, that is
+
+ (subreg:MODE (plus (A) (-C1))) op (C2)
+
+ with C1 a constant, and try to lift the SUBREG, i.e. to do the
+ comparison in the wider mode. One of the following two conditions
+ must be true in order for this to be valid:
+
+ 1. The mode extension results in the same bit pattern being added
+ on both sides and the comparison is equality or unsigned. As
+ C2 has been truncated to fit in MODE, the pattern can only be
+ all 0s or all 1s.
+
+ 2. The mode extension results in the sign bit being copied on
+ each side.
+
+ The difficulty here is that we have predicates for A but not for
+ (A - C1) so we need to check that C1 is within proper bounds so
+ as to perturbate A as little as possible. */
+
+ if (mode_width <= HOST_BITS_PER_WIDE_INT
+ && subreg_lowpart_p (op0)
+ && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (op0)),
+ &inner_mode)
+ && GET_MODE_PRECISION (inner_mode) > mode_width
+ && GET_CODE (SUBREG_REG (op0)) == PLUS
+ && CONST_INT_P (XEXP (SUBREG_REG (op0), 1)))
+ {
+ rtx a = XEXP (SUBREG_REG (op0), 0);
+ HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
+
+ if ((c1 > 0
+ && (unsigned HOST_WIDE_INT) c1
+ < HOST_WIDE_INT_1U << (mode_width - 1)
+ && (equality_comparison_p || unsigned_comparison_p)
+ /* (A - C1) zero-extends if it is positive and sign-extends
+ if it is negative, C2 both zero- and sign-extends. */
+ && (((nonzero_bits (a, inner_mode)
+ & ~GET_MODE_MASK (mode)) == 0
+ && const_op >= 0)
+ /* (A - C1) sign-extends if it is positive and 1-extends
+ if it is negative, C2 both sign- and 1-extends. */
+ || (num_sign_bit_copies (a, inner_mode)
+ > (unsigned int) (GET_MODE_PRECISION (inner_mode)
+ - mode_width)
+ && const_op < 0)))
+ || ((unsigned HOST_WIDE_INT) c1
+ < HOST_WIDE_INT_1U << (mode_width - 2)
+ /* (A - C1) always sign-extends, like C2. */
+ && num_sign_bit_copies (a, inner_mode)
+ > (unsigned int) (GET_MODE_PRECISION (inner_mode)
+ - (mode_width - 1))))
+ {
+ op0 = SUBREG_REG (op0);
+ continue;
+ }
+ }
+
+ /* If the inner mode is narrower and we are extracting the low part,
+ we can treat the SUBREG as if it were a ZERO_EXTEND. */
+ if (paradoxical_subreg_p (op0))
+ ;
+ else if (subreg_lowpart_p (op0)
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && is_int_mode (GET_MODE (SUBREG_REG (op0)), &inner_mode)
+ && (code == NE || code == EQ)
+ && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
+ && !paradoxical_subreg_p (op0)
+ && (nonzero_bits (SUBREG_REG (op0), inner_mode)
+ & ~GET_MODE_MASK (mode)) == 0)
+ {
+ /* Remove outer subregs that don't do anything. */
+ tem = gen_lowpart (inner_mode, op1);
+
+ if ((nonzero_bits (tem, inner_mode)
+ & ~GET_MODE_MASK (mode)) == 0)
+ {
+ op0 = SUBREG_REG (op0);
+ op1 = tem;
+ continue;
+ }
+ break;
+ }
+ else
+ break;
+
+ /* FALLTHROUGH */
+
+ case ZERO_EXTEND:
+ if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
+ && (unsigned_comparison_p || equality_comparison_p)
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
+ && const_op >= 0
+ && have_insn_for (COMPARE, mode))
+ {
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+ break;
+
+ case PLUS:
+ /* (eq (plus X A) B) -> (eq X (minus B A)). We can only do
+ this for equality comparisons due to pathological cases involving
+ overflows. */
+ if (equality_comparison_p
+ && (tem = simplify_binary_operation (MINUS, mode,
+ op1, XEXP (op0, 1))) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ /* (plus (abs X) (const_int -1)) is < 0 if and only if X == 0. */
+ if (const_op == 0 && XEXP (op0, 1) == constm1_rtx
+ && GET_CODE (XEXP (op0, 0)) == ABS && sign_bit_comparison_p)
+ {
+ op0 = XEXP (XEXP (op0, 0), 0);
+ code = (code == LT ? EQ : NE);
+ continue;
+ }
+ break;
+
+ case MINUS:
+ /* We used to optimize signed comparisons against zero, but that
+ was incorrect. Unsigned comparisons against zero (GTU, LEU)
+ arrive here as equality comparisons, or (GEU, LTU) are
+ optimized away. No need to special-case them. */
+
+ /* (eq (minus A B) C) -> (eq A (plus B C)) or
+ (eq B (minus A C)), whichever simplifies. We can only do
+ this for equality comparisons due to pathological cases involving
+ overflows. */
+ if (equality_comparison_p
+ && (tem = simplify_binary_operation (PLUS, mode,
+ XEXP (op0, 1), op1)) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ if (equality_comparison_p
+ && (tem = simplify_binary_operation (MINUS, mode,
+ XEXP (op0, 0), op1)) != 0)
+ {
+ op0 = XEXP (op0, 1);
+ op1 = tem;
+ continue;
+ }
+
+ /* The sign bit of (minus (ashiftrt X C) X), where C is the number
+ of bits in X minus 1, is one iff X > 0. */
+ if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
+ && UINTVAL (XEXP (XEXP (op0, 0), 1)) == mode_width - 1
+ && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
+ {
+ op0 = XEXP (op0, 1);
+ code = (code == GE ? LE : GT);
+ continue;
+ }
+ break;
+
+ case XOR:
+ /* (eq (xor A B) C) -> (eq A (xor B C)). This is a simplification
+ if C is zero or B is a constant. */
+ if (equality_comparison_p
+ && (tem = simplify_binary_operation (XOR, mode,
+ XEXP (op0, 1), op1)) != 0)
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+ break;
+
+
+ case IOR:
+ /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
+ iff X <= 0. */
+ if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS
+ && XEXP (XEXP (op0, 0), 1) == constm1_rtx
+ && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
+ {
+ op0 = XEXP (op0, 1);
+ code = (code == GE ? GT : LE);
+ continue;
+ }
+ break;
+
+ case AND:
+ /* Convert (and (xshift 1 X) Y) to (and (lshiftrt Y X) 1). This
+ will be converted to a ZERO_EXTRACT later. */
+ if (const_op == 0 && equality_comparison_p
+ && GET_CODE (XEXP (op0, 0)) == ASHIFT
+ && XEXP (XEXP (op0, 0), 0) == const1_rtx)
+ {
+ op0 = gen_rtx_LSHIFTRT (mode, XEXP (op0, 1),
+ XEXP (XEXP (op0, 0), 1));
+ op0 = simplify_and_const_int (NULL_RTX, mode, op0, 1);
+ continue;
+ }
+
+ /* If we are comparing (and (lshiftrt X C1) C2) for equality with
+ zero and X is a comparison and C1 and C2 describe only bits set
+ in STORE_FLAG_VALUE, we can compare with X. */
+ if (const_op == 0 && equality_comparison_p
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && CONST_INT_P (XEXP (op0, 1))
+ && GET_CODE (XEXP (op0, 0)) == LSHIFTRT
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
+ && INTVAL (XEXP (XEXP (op0, 0), 1)) >= 0
+ && INTVAL (XEXP (XEXP (op0, 0), 1)) < HOST_BITS_PER_WIDE_INT)
+ {
+ mask = ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
+ << INTVAL (XEXP (XEXP (op0, 0), 1)));
+ if ((~STORE_FLAG_VALUE & mask) == 0
+ && (COMPARISON_P (XEXP (XEXP (op0, 0), 0))
+ || ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0
+ && COMPARISON_P (tem))))
+ {
+ op0 = XEXP (XEXP (op0, 0), 0);
+ continue;
+ }
+ }
+
+ /* If we are doing an equality comparison of an AND of a bit equal
+ to the sign bit, replace this with a LT or GE comparison of
+ the underlying value. */
+ if (equality_comparison_p
+ && const_op == 0
+ && CONST_INT_P (XEXP (op0, 1))
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
+ == HOST_WIDE_INT_1U << (mode_width - 1)))
+ {
+ op0 = XEXP (op0, 0);
+ code = (code == EQ ? GE : LT);
+ continue;
+ }
+
+ /* If this AND operation is really a ZERO_EXTEND from a narrower
+ mode, the constant fits within that mode, and this is either an
+ equality or unsigned comparison, try to do this comparison in
+ the narrower mode.
+
+ Note that in:
+
+ (ne:DI (and:DI (reg:DI 4) (const_int 0xffffffff)) (const_int 0))
+ -> (ne:DI (reg:SI 4) (const_int 0))
+
+ unless TARGET_TRULY_NOOP_TRUNCATION allows it or the register is
+ known to hold a value of the required mode the
+ transformation is invalid. */
+ if ((equality_comparison_p || unsigned_comparison_p)
+ && CONST_INT_P (XEXP (op0, 1))
+ && (i = exact_log2 ((UINTVAL (XEXP (op0, 1))
+ & GET_MODE_MASK (mode))
+ + 1)) >= 0
+ && const_op >> i == 0
+ && int_mode_for_size (i, 1).exists (&tmode))
+ {
+ op0 = gen_lowpart_or_truncate (tmode, XEXP (op0, 0));
+ continue;
+ }
+
+ /* If this is (and:M1 (subreg:M1 X:M2 0) (const_int C1)) where C1
+ fits in both M1 and M2 and the SUBREG is either paradoxical
+ or represents the low part, permute the SUBREG and the AND
+ and try again. */
+ if (GET_CODE (XEXP (op0, 0)) == SUBREG
+ && CONST_INT_P (XEXP (op0, 1)))
+ {
+ unsigned HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1));
+ /* Require an integral mode, to avoid creating something like
+ (AND:SF ...). */
+ if ((is_a <scalar_int_mode>
+ (GET_MODE (SUBREG_REG (XEXP (op0, 0))), &tmode))
+ /* It is unsafe to commute the AND into the SUBREG if the
+ SUBREG is paradoxical and WORD_REGISTER_OPERATIONS is
+ not defined. As originally written the upper bits
+ have a defined value due to the AND operation.
+ However, if we commute the AND inside the SUBREG then
+ they no longer have defined values and the meaning of
+ the code has been changed.
+ Also C1 should not change value in the smaller mode,
+ see PR67028 (a positive C1 can become negative in the
+ smaller mode, so that the AND does no longer mask the
+ upper bits). */
+ && ((WORD_REGISTER_OPERATIONS
+ && mode_width > GET_MODE_PRECISION (tmode)
+ && mode_width <= BITS_PER_WORD
+ && trunc_int_for_mode (c1, tmode) == (HOST_WIDE_INT) c1)
+ || (mode_width <= GET_MODE_PRECISION (tmode)
+ && subreg_lowpart_p (XEXP (op0, 0))))
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && HWI_COMPUTABLE_MODE_P (tmode)
+ && (c1 & ~mask) == 0
+ && (c1 & ~GET_MODE_MASK (tmode)) == 0
+ && c1 != mask
+ && c1 != GET_MODE_MASK (tmode))
+ {
+ op0 = simplify_gen_binary (AND, tmode,
+ SUBREG_REG (XEXP (op0, 0)),
+ gen_int_mode (c1, tmode));
+ op0 = gen_lowpart (mode, op0);
+ continue;
+ }
+ }
+
+ /* Convert (ne (and (not X) 1) 0) to (eq (and X 1) 0). */
+ if (const_op == 0 && equality_comparison_p
+ && XEXP (op0, 1) == const1_rtx
+ && GET_CODE (XEXP (op0, 0)) == NOT)
+ {
+ op0 = simplify_and_const_int (NULL_RTX, mode,
+ XEXP (XEXP (op0, 0), 0), 1);
+ code = (code == NE ? EQ : NE);
+ continue;
+ }
+
+ /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
+ (eq (and (lshiftrt X) 1) 0).
+ Also handle the case where (not X) is expressed using xor. */
+ if (const_op == 0 && equality_comparison_p
+ && XEXP (op0, 1) == const1_rtx
+ && GET_CODE (XEXP (op0, 0)) == LSHIFTRT)
+ {
+ rtx shift_op = XEXP (XEXP (op0, 0), 0);
+ rtx shift_count = XEXP (XEXP (op0, 0), 1);
+
+ if (GET_CODE (shift_op) == NOT
+ || (GET_CODE (shift_op) == XOR
+ && CONST_INT_P (XEXP (shift_op, 1))
+ && CONST_INT_P (shift_count)
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && (UINTVAL (XEXP (shift_op, 1))
+ == HOST_WIDE_INT_1U
+ << INTVAL (shift_count))))
+ {
+ op0
+ = gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count);
+ op0 = simplify_and_const_int (NULL_RTX, mode, op0, 1);
+ code = (code == NE ? EQ : NE);
+ continue;
+ }
+ }
+ break;
+
+ case ASHIFT:
+ /* If we have (compare (ashift FOO N) (const_int C)) and
+ the high order N bits of FOO (N+1 if an inequality comparison)
+ are known to be zero, we can do this by comparing FOO with C
+ shifted right N bits so long as the low-order N bits of C are
+ zero. */
+ if (CONST_INT_P (XEXP (op0, 1))
+ && INTVAL (XEXP (op0, 1)) >= 0
+ && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
+ < HOST_BITS_PER_WIDE_INT)
+ && (((unsigned HOST_WIDE_INT) const_op
+ & ((HOST_WIDE_INT_1U << INTVAL (XEXP (op0, 1)))
+ - 1)) == 0)
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (op0, 0), mode)
+ & ~(mask >> (INTVAL (XEXP (op0, 1))
+ + ! equality_comparison_p))) == 0)
+ {
+ /* We must perform a logical shift, not an arithmetic one,
+ as we want the top N bits of C to be zero. */
+ unsigned HOST_WIDE_INT temp = const_op & GET_MODE_MASK (mode);
+
+ temp >>= INTVAL (XEXP (op0, 1));
+ op1 = gen_int_mode (temp, mode);
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+
+ /* If we are doing a sign bit comparison, it means we are testing
+ a particular bit. Convert it to the appropriate AND. */
+ if (sign_bit_comparison_p && CONST_INT_P (XEXP (op0, 1))
+ && mode_width <= HOST_BITS_PER_WIDE_INT)
+ {
+ op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
+ (HOST_WIDE_INT_1U
+ << (mode_width - 1
+ - INTVAL (XEXP (op0, 1)))));
+ code = (code == LT ? NE : EQ);
+ continue;
+ }
+
+ /* If this an equality comparison with zero and we are shifting
+ the low bit to the sign bit, we can convert this to an AND of the
+ low-order bit. */
+ if (const_op == 0 && equality_comparison_p
+ && CONST_INT_P (XEXP (op0, 1))
+ && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
+ {
+ op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), 1);
+ continue;
+ }
+ break;
+
+ case ASHIFTRT:
+ /* If this is an equality comparison with zero, we can do this
+ as a logical shift, which might be much simpler. */
+ if (equality_comparison_p && const_op == 0
+ && CONST_INT_P (XEXP (op0, 1)))
+ {
+ op0 = simplify_shift_const (NULL_RTX, LSHIFTRT, mode,
+ XEXP (op0, 0),
+ INTVAL (XEXP (op0, 1)));
+ continue;
+ }
+
+ /* If OP0 is a sign extension and CODE is not an unsigned comparison,
+ do the comparison in a narrower mode. */
+ if (! unsigned_comparison_p
+ && CONST_INT_P (XEXP (op0, 1))
+ && GET_CODE (XEXP (op0, 0)) == ASHIFT
+ && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
+ && (int_mode_for_size (mode_width - INTVAL (XEXP (op0, 1)), 1)
+ .exists (&tmode))
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_MODE_MASK (tmode) >> 1) + 1)
+ <= GET_MODE_MASK (tmode)))
+ {
+ op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
+ continue;
+ }
+
+ /* Likewise if OP0 is a PLUS of a sign extension with a
+ constant, which is usually represented with the PLUS
+ between the shifts. */
+ if (! unsigned_comparison_p
+ && CONST_INT_P (XEXP (op0, 1))
+ && GET_CODE (XEXP (op0, 0)) == PLUS
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
+ && GET_CODE (XEXP (XEXP (op0, 0), 0)) == ASHIFT
+ && XEXP (op0, 1) == XEXP (XEXP (XEXP (op0, 0), 0), 1)
+ && (int_mode_for_size (mode_width - INTVAL (XEXP (op0, 1)), 1)
+ .exists (&tmode))
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_MODE_MASK (tmode) >> 1) + 1)
+ <= GET_MODE_MASK (tmode)))
+ {
+ rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
+ rtx add_const = XEXP (XEXP (op0, 0), 1);
+ rtx new_const = simplify_gen_binary (ASHIFTRT, mode,
+ add_const, XEXP (op0, 1));
+
+ op0 = simplify_gen_binary (PLUS, tmode,
+ gen_lowpart (tmode, inner),
+ new_const);
+ continue;
+ }
+
+ /* FALLTHROUGH */
+ case LSHIFTRT:
+ /* If we have (compare (xshiftrt FOO N) (const_int C)) and
+ the low order N bits of FOO are known to be zero, we can do this
+ by comparing FOO with C shifted left N bits so long as no
+ overflow occurs. Even if the low order N bits of FOO aren't known
+ to be zero, if the comparison is >= or < we can use the same
+ optimization and for > or <= by setting all the low
+ order N bits in the comparison constant. */
+ if (CONST_INT_P (XEXP (op0, 1))
+ && INTVAL (XEXP (op0, 1)) > 0
+ && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && (((unsigned HOST_WIDE_INT) const_op
+ + (GET_CODE (op0) != LSHIFTRT
+ ? ((GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1)) >> 1)
+ + 1)
+ : 0))
+ <= GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1))))
+ {
+ unsigned HOST_WIDE_INT low_bits
+ = (nonzero_bits (XEXP (op0, 0), mode)
+ & ((HOST_WIDE_INT_1U
+ << INTVAL (XEXP (op0, 1))) - 1));
+ if (low_bits == 0 || !equality_comparison_p)
+ {
+ /* If the shift was logical, then we must make the condition
+ unsigned. */
+ if (GET_CODE (op0) == LSHIFTRT)
+ code = unsigned_condition (code);
+
+ const_op = (unsigned HOST_WIDE_INT) const_op
+ << INTVAL (XEXP (op0, 1));
+ if (low_bits != 0
+ && (code == GT || code == GTU
+ || code == LE || code == LEU))
+ const_op
+ |= ((HOST_WIDE_INT_1 << INTVAL (XEXP (op0, 1))) - 1);
+ op1 = GEN_INT (const_op);
+ op0 = XEXP (op0, 0);
+ continue;
+ }
+ }
+
+ /* If we are using this shift to extract just the sign bit, we
+ can replace this with an LT or GE comparison. */
+ if (const_op == 0
+ && (equality_comparison_p || sign_bit_comparison_p)
+ && CONST_INT_P (XEXP (op0, 1))
+ && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
+ {
+ op0 = XEXP (op0, 0);
+ code = (code == NE || code == GT ? LT : GE);
+ continue;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ /* Now make any compound operations involved in this comparison. Then,
+ check for an outmost SUBREG on OP0 that is not doing anything or is
+ paradoxical. The latter transformation must only be performed when
+ it is known that the "extra" bits will be the same in op0 and op1 or
+ that they don't matter. There are three cases to consider:
+
+ 1. SUBREG_REG (op0) is a register. In this case the bits are don't
+ care bits and we can assume they have any convenient value. So
+ making the transformation is safe.
+
+ 2. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is UNKNOWN.
+ In this case the upper bits of op0 are undefined. We should not make
+ the simplification in that case as we do not know the contents of
+ those bits.
+
+ 3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is not UNKNOWN.
+ In that case we know those bits are zeros or ones. We must also be
+ sure that they are the same as the upper bits of op1.
+
+ We can never remove a SUBREG for a non-equality comparison because
+ the sign bit is in a different place in the underlying object. */
+
+ rtx_code op0_mco_code = SET;
+ if (op1 == const0_rtx)
+ op0_mco_code = code == NE || code == EQ ? EQ : COMPARE;
+
+ op0 = make_compound_operation (op0, op0_mco_code);
+ op1 = make_compound_operation (op1, SET);
+
+ if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
+ && is_int_mode (GET_MODE (op0), &mode)
+ && is_int_mode (GET_MODE (SUBREG_REG (op0)), &inner_mode)
+ && (code == NE || code == EQ))
+ {
+ if (paradoxical_subreg_p (op0))
+ {
+ /* For paradoxical subregs, allow case 1 as above. Case 3 isn't
+ implemented. */
+ if (REG_P (SUBREG_REG (op0)))
+ {
+ op0 = SUBREG_REG (op0);
+ op1 = gen_lowpart (inner_mode, op1);
+ }
+ }
+ else if (GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (SUBREG_REG (op0), inner_mode)
+ & ~GET_MODE_MASK (mode)) == 0)
+ {
+ tem = gen_lowpart (inner_mode, op1);
+
+ if ((nonzero_bits (tem, inner_mode) & ~GET_MODE_MASK (mode)) == 0)
+ op0 = SUBREG_REG (op0), op1 = tem;
+ }
+ }
+
+ /* We now do the opposite procedure: Some machines don't have compare
+ insns in all modes. If OP0's mode is an integer mode smaller than a
+ word and we can't do a compare in that mode, see if there is a larger
+ mode for which we can do the compare. There are a number of cases in
+ which we can use the wider mode. */
+
+ if (is_int_mode (GET_MODE (op0), &mode)
+ && GET_MODE_SIZE (mode) < UNITS_PER_WORD
+ && ! have_insn_for (COMPARE, mode))
+ FOR_EACH_WIDER_MODE (tmode_iter, mode)
+ {
+ tmode = tmode_iter.require ();
+ if (!HWI_COMPUTABLE_MODE_P (tmode))
+ break;
+ if (have_insn_for (COMPARE, tmode))
+ {
+ int zero_extended;
+
+ /* If this is a test for negative, we can make an explicit
+ test of the sign bit. Test this first so we can use
+ a paradoxical subreg to extend OP0. */
+
+ if (op1 == const0_rtx && (code == LT || code == GE)
+ && HWI_COMPUTABLE_MODE_P (mode))
+ {
+ unsigned HOST_WIDE_INT sign
+ = HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (mode) - 1);
+ op0 = simplify_gen_binary (AND, tmode,
+ gen_lowpart (tmode, op0),
+ gen_int_mode (sign, tmode));
+ code = (code == LT) ? NE : EQ;
+ break;
+ }
+
+ /* If the only nonzero bits in OP0 and OP1 are those in the
+ narrower mode and this is an equality or unsigned comparison,
+ we can use the wider mode. Similarly for sign-extended
+ values, in which case it is true for all comparisons. */
+ zero_extended = ((code == EQ || code == NE
+ || code == GEU || code == GTU
+ || code == LEU || code == LTU)
+ && (nonzero_bits (op0, tmode)
+ & ~GET_MODE_MASK (mode)) == 0
+ && ((CONST_INT_P (op1)
+ || (nonzero_bits (op1, tmode)
+ & ~GET_MODE_MASK (mode)) == 0)));
+
+ if (zero_extended
+ || ((num_sign_bit_copies (op0, tmode)
+ > (unsigned int) (GET_MODE_PRECISION (tmode)
+ - GET_MODE_PRECISION (mode)))
+ && (num_sign_bit_copies (op1, tmode)
+ > (unsigned int) (GET_MODE_PRECISION (tmode)
+ - GET_MODE_PRECISION (mode)))))
+ {
+ /* If OP0 is an AND and we don't have an AND in MODE either,
+ make a new AND in the proper mode. */
+ if (GET_CODE (op0) == AND
+ && !have_insn_for (AND, mode))
+ op0 = simplify_gen_binary (AND, tmode,
+ gen_lowpart (tmode,
+ XEXP (op0, 0)),
+ gen_lowpart (tmode,
+ XEXP (op0, 1)));
+ else
+ {
+ if (zero_extended)
+ {
+ op0 = simplify_gen_unary (ZERO_EXTEND, tmode,
+ op0, mode);
+ op1 = simplify_gen_unary (ZERO_EXTEND, tmode,
+ op1, mode);
+ }
+ else
+ {
+ op0 = simplify_gen_unary (SIGN_EXTEND, tmode,
+ op0, mode);
+ op1 = simplify_gen_unary (SIGN_EXTEND, tmode,
+ op1, mode);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* We may have changed the comparison operands. Re-canonicalize. */
+ if (swap_commutative_operands_p (op0, op1))
+ {
+ std::swap (op0, op1);
+ code = swap_condition (code);
+ }
+
+ /* If this machine only supports a subset of valid comparisons, see if we
+ can convert an unsupported one into a supported one. */
+ target_canonicalize_comparison (&code, &op0, &op1, 0);
+
+ *pop0 = op0;
+ *pop1 = op1;
+
+ return code;
+}
+
+/* Utility function for record_value_for_reg. Count number of
+ rtxs in X. */
+static int
+count_rtxs (rtx x)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt;
+ int i, j, ret = 1;
+
+ if (GET_RTX_CLASS (code) == RTX_BIN_ARITH
+ || GET_RTX_CLASS (code) == RTX_COMM_ARITH)
+ {
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ if (x0 == x1)
+ return 1 + 2 * count_rtxs (x0);
+
+ if ((GET_RTX_CLASS (GET_CODE (x1)) == RTX_BIN_ARITH
+ || GET_RTX_CLASS (GET_CODE (x1)) == RTX_COMM_ARITH)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ return 2 + 2 * count_rtxs (x0)
+ + count_rtxs (x == XEXP (x1, 0)
+ ? XEXP (x1, 1) : XEXP (x1, 0));
+
+ if ((GET_RTX_CLASS (GET_CODE (x0)) == RTX_BIN_ARITH
+ || GET_RTX_CLASS (GET_CODE (x0)) == RTX_COMM_ARITH)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ return 2 + 2 * count_rtxs (x1)
+ + count_rtxs (x == XEXP (x0, 0)
+ ? XEXP (x0, 1) : XEXP (x0, 0));
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ ret += count_rtxs (XEXP (x, i));
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ ret += count_rtxs (XVECEXP (x, i, j));
+
+ return ret;
+}
+
+/* Utility function for following routine. Called when X is part of a value
+ being stored into last_set_value. Sets last_set_table_tick
+ for each register mentioned. Similar to mention_regs in cse.c */
+
+static void
+update_table_tick (rtx x)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i, j;
+
+ if (code == REG)
+ {
+ unsigned int regno = REGNO (x);
+ unsigned int endregno = END_REGNO (x);
+ unsigned int r;
+
+ for (r = regno; r < endregno; r++)
+ {
+ reg_stat_type *rsp = &reg_stat[r];
+ rsp->last_set_table_tick = label_tick;
+ }
+
+ return;
+ }
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ {
+ /* Check for identical subexpressions. If x contains
+ identical subexpression we only have to traverse one of
+ them. */
+ if (i == 0 && ARITHMETIC_P (x))
+ {
+ /* Note that at this point x1 has already been
+ processed. */
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* If x0 and x1 are identical then there is no need to
+ process x0. */
+ if (x0 == x1)
+ break;
+
+ /* If x0 is identical to a subexpression of x1 then while
+ processing x1, x0 has already been processed. Thus we
+ are done with x. */
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ break;
+
+ /* If x1 is identical to a subexpression of x0 then we
+ still have to process the rest of x0. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ {
+ update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0));
+ break;
+ }
+ }
+
+ update_table_tick (XEXP (x, i));
+ }
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ update_table_tick (XVECEXP (x, i, j));
+}
+
+/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we
+ are saying that the register is clobbered and we no longer know its
+ value. If INSN is zero, don't update reg_stat[].last_set; this is
+ only permitted with VALUE also zero and is used to invalidate the
+ register. */
+
+static void
+record_value_for_reg (rtx reg, rtx_insn *insn, rtx value)
+{
+ unsigned int regno = REGNO (reg);
+ unsigned int endregno = END_REGNO (reg);
+ unsigned int i;
+ reg_stat_type *rsp;
+
+ /* If VALUE contains REG and we have a previous value for REG, substitute
+ the previous value. */
+ if (value && insn && reg_overlap_mentioned_p (reg, value))
+ {
+ rtx tem;
+
+ /* Set things up so get_last_value is allowed to see anything set up to
+ our insn. */
+ subst_low_luid = DF_INSN_LUID (insn);
+ tem = get_last_value (reg);
+
+ /* If TEM is simply a binary operation with two CLOBBERs as operands,
+ it isn't going to be useful and will take a lot of time to process,
+ so just use the CLOBBER. */
+
+ if (tem)
+ {
+ if (ARITHMETIC_P (tem)
+ && GET_CODE (XEXP (tem, 0)) == CLOBBER
+ && GET_CODE (XEXP (tem, 1)) == CLOBBER)
+ tem = XEXP (tem, 0);
+ else if (count_occurrences (value, reg, 1) >= 2)
+ {
+ /* If there are two or more occurrences of REG in VALUE,
+ prevent the value from growing too much. */
+ if (count_rtxs (tem) > param_max_last_value_rtl)
+ tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
+ }
+
+ value = replace_rtx (copy_rtx (value), reg, tem);
+ }
+ }
+
+ /* For each register modified, show we don't know its value, that
+ we don't know about its bitwise content, that its value has been
+ updated, and that we don't know the location of the death of the
+ register. */
+ for (i = regno; i < endregno; i++)
+ {
+ rsp = &reg_stat[i];
+
+ if (insn)
+ rsp->last_set = insn;
+
+ rsp->last_set_value = 0;
+ rsp->last_set_mode = VOIDmode;
+ rsp->last_set_nonzero_bits = 0;
+ rsp->last_set_sign_bit_copies = 0;
+ rsp->last_death = 0;
+ rsp->truncated_to_mode = VOIDmode;
+ }
+
+ /* Mark registers that are being referenced in this value. */
+ if (value)
+ update_table_tick (value);
+
+ /* Now update the status of each register being set.
+ If someone is using this register in this block, set this register
+ to invalid since we will get confused between the two lives in this
+ basic block. This makes using this register always invalid. In cse, we
+ scan the table to invalidate all entries using this register, but this
+ is too much work for us. */
+
+ for (i = regno; i < endregno; i++)
+ {
+ rsp = &reg_stat[i];
+ rsp->last_set_label = label_tick;
+ if (!insn
+ || (value && rsp->last_set_table_tick >= label_tick_ebb_start))
+ rsp->last_set_invalid = 1;
+ else
+ rsp->last_set_invalid = 0;
+ }
+
+ /* The value being assigned might refer to X (like in "x++;"). In that
+ case, we must replace it with (clobber (const_int 0)) to prevent
+ infinite loops. */
+ rsp = &reg_stat[regno];
+ if (value && !get_last_value_validate (&value, insn, label_tick, 0))
+ {
+ value = copy_rtx (value);
+ if (!get_last_value_validate (&value, insn, label_tick, 1))
+ value = 0;
+ }
+
+ /* For the main register being modified, update the value, the mode, the
+ nonzero bits, and the number of sign bit copies. */
+
+ rsp->last_set_value = value;
+
+ if (value)
+ {
+ machine_mode mode = GET_MODE (reg);
+ subst_low_luid = DF_INSN_LUID (insn);
+ rsp->last_set_mode = mode;
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && HWI_COMPUTABLE_MODE_P (mode))
+ mode = nonzero_bits_mode;
+ rsp->last_set_nonzero_bits = nonzero_bits (value, mode);
+ rsp->last_set_sign_bit_copies
+ = num_sign_bit_copies (value, GET_MODE (reg));
+ }
+}
+
+/* Called via note_stores from record_dead_and_set_regs to handle one
+ SET or CLOBBER in an insn. DATA is the instruction in which the
+ set is occurring. */
+
+static void
+record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
+{
+ rtx_insn *record_dead_insn = (rtx_insn *) data;
+
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ if (!record_dead_insn)
+ {
+ if (REG_P (dest))
+ record_value_for_reg (dest, NULL, NULL_RTX);
+ return;
+ }
+
+ if (REG_P (dest))
+ {
+ /* If we are setting the whole register, we know its value. Otherwise
+ show that we don't know the value. We can handle a SUBREG if it's
+ the low part, but we must be careful with paradoxical SUBREGs on
+ RISC architectures because we cannot strip e.g. an extension around
+ a load and record the naked load since the RTL middle-end considers
+ that the upper bits are defined according to LOAD_EXTEND_OP. */
+ if (GET_CODE (setter) == SET && dest == SET_DEST (setter))
+ record_value_for_reg (dest, record_dead_insn, SET_SRC (setter));
+ else if (GET_CODE (setter) == SET
+ && GET_CODE (SET_DEST (setter)) == SUBREG
+ && SUBREG_REG (SET_DEST (setter)) == dest
+ && known_le (GET_MODE_PRECISION (GET_MODE (dest)),
+ BITS_PER_WORD)
+ && subreg_lowpart_p (SET_DEST (setter)))
+ record_value_for_reg (dest, record_dead_insn,
+ WORD_REGISTER_OPERATIONS
+ && word_register_operation_p (SET_SRC (setter))
+ && paradoxical_subreg_p (SET_DEST (setter))
+ ? SET_SRC (setter)
+ : gen_lowpart (GET_MODE (dest),
+ SET_SRC (setter)));
+ else
+ record_value_for_reg (dest, record_dead_insn, NULL_RTX);
+ }
+ else if (MEM_P (dest)
+ /* Ignore pushes, they clobber nothing. */
+ && ! push_operand (dest, GET_MODE (dest)))
+ mem_last_set = DF_INSN_LUID (record_dead_insn);
+}
+
+/* Update the records of when each REG was most recently set or killed
+ for the things done by INSN. This is the last thing done in processing
+ INSN in the combiner loop.
+
+ We update reg_stat[], in particular fields last_set, last_set_value,
+ last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
+ last_death, and also the similar information mem_last_set (which insn
+ most recently modified memory) and last_call_luid (which insn was the
+ most recent subroutine call). */
+
+static void
+record_dead_and_set_regs (rtx_insn *insn)
+{
+ rtx link;
+ unsigned int i;
+
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ {
+ if (REG_NOTE_KIND (link) == REG_DEAD
+ && REG_P (XEXP (link, 0)))
+ {
+ unsigned int regno = REGNO (XEXP (link, 0));
+ unsigned int endregno = END_REGNO (XEXP (link, 0));
+
+ for (i = regno; i < endregno; i++)
+ {
+ reg_stat_type *rsp;
+
+ rsp = &reg_stat[i];
+ rsp->last_death = insn;
+ }
+ }
+ else if (REG_NOTE_KIND (link) == REG_INC)
+ record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
+ }
+
+ if (CALL_P (insn))
+ {
+ HARD_REG_SET callee_clobbers
+ = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
+ hard_reg_set_iterator hrsi;
+ EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, i, hrsi)
+ {
+ reg_stat_type *rsp;
+
+ /* ??? We could try to preserve some information from the last
+ set of register I if the call doesn't actually clobber
+ (reg:last_set_mode I), which might be true for ABIs with
+ partial clobbers. However, it would be difficult to
+ update last_set_nonzero_bits and last_sign_bit_copies
+ to account for the part of I that actually was clobbered.
+ It wouldn't help much anyway, since we rarely see this
+ situation before RA. */
+ rsp = &reg_stat[i];
+ rsp->last_set_invalid = 1;
+ rsp->last_set = insn;
+ rsp->last_set_value = 0;
+ rsp->last_set_mode = VOIDmode;
+ rsp->last_set_nonzero_bits = 0;
+ rsp->last_set_sign_bit_copies = 0;
+ rsp->last_death = 0;
+ rsp->truncated_to_mode = VOIDmode;
+ }
+
+ last_call_luid = mem_last_set = DF_INSN_LUID (insn);
+
+ /* We can't combine into a call pattern. Remember, though, that
+ the return value register is set at this LUID. We could
+ still replace a register with the return value from the
+ wrong subroutine call! */
+ note_stores (insn, record_dead_and_set_regs_1, NULL_RTX);
+ }
+ else
+ note_stores (insn, record_dead_and_set_regs_1, insn);
+}
+
+/* If a SUBREG has the promoted bit set, it is in fact a property of the
+ register present in the SUBREG, so for each such SUBREG go back and
+ adjust nonzero and sign bit information of the registers that are
+ known to have some zero/sign bits set.
+
+ This is needed because when combine blows the SUBREGs away, the
+ information on zero/sign bits is lost and further combines can be
+ missed because of that. */
+
+static void
+record_promoted_value (rtx_insn *insn, rtx subreg)
+{
+ struct insn_link *links;
+ rtx set;
+ unsigned int regno = REGNO (SUBREG_REG (subreg));
+ machine_mode mode = GET_MODE (subreg);
+
+ if (!HWI_COMPUTABLE_MODE_P (mode))
+ return;
+
+ for (links = LOG_LINKS (insn); links;)
+ {
+ reg_stat_type *rsp;
+
+ insn = links->insn;
+ set = single_set (insn);
+
+ if (! set || !REG_P (SET_DEST (set))
+ || REGNO (SET_DEST (set)) != regno
+ || GET_MODE (SET_DEST (set)) != GET_MODE (SUBREG_REG (subreg)))
+ {
+ links = links->next;
+ continue;
+ }
+
+ rsp = &reg_stat[regno];
+ if (rsp->last_set == insn)
+ {
+ if (SUBREG_PROMOTED_UNSIGNED_P (subreg))
+ rsp->last_set_nonzero_bits &= GET_MODE_MASK (mode);
+ }
+
+ if (REG_P (SET_SRC (set)))
+ {
+ regno = REGNO (SET_SRC (set));
+ links = LOG_LINKS (insn);
+ }
+ else
+ break;
+ }
+}
+
+/* Check if X, a register, is known to contain a value already
+ truncated to MODE. In this case we can use a subreg to refer to
+ the truncated value even though in the generic case we would need
+ an explicit truncation. */
+
+static bool
+reg_truncated_to_mode (machine_mode mode, const_rtx x)
+{
+ reg_stat_type *rsp = &reg_stat[REGNO (x)];
+ machine_mode truncated = rsp->truncated_to_mode;
+
+ if (truncated == 0
+ || rsp->truncation_label < label_tick_ebb_start)
+ return false;
+ if (!partial_subreg_p (mode, truncated))
+ return true;
+ if (TRULY_NOOP_TRUNCATION_MODES_P (mode, truncated))
+ return true;
+ return false;
+}
+
+/* If X is a hard reg or a subreg record the mode that the register is
+ accessed in. For non-TARGET_TRULY_NOOP_TRUNCATION targets we might be
+ able to turn a truncate into a subreg using this information. Return true
+ if traversing X is complete. */
+
+static bool
+record_truncated_value (rtx x)
+{
+ machine_mode truncated_mode;
+ reg_stat_type *rsp;
+
+ if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))
+ {
+ machine_mode original_mode = GET_MODE (SUBREG_REG (x));
+ truncated_mode = GET_MODE (x);
+
+ if (!partial_subreg_p (truncated_mode, original_mode))
+ return true;
+
+ truncated_mode = GET_MODE (x);
+ if (TRULY_NOOP_TRUNCATION_MODES_P (truncated_mode, original_mode))
+ return true;
+
+ x = SUBREG_REG (x);
+ }
+ /* ??? For hard-regs we now record everything. We might be able to
+ optimize this using last_set_mode. */
+ else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ truncated_mode = GET_MODE (x);
+ else
+ return false;
+
+ rsp = &reg_stat[REGNO (x)];
+ if (rsp->truncated_to_mode == 0
+ || rsp->truncation_label < label_tick_ebb_start
+ || partial_subreg_p (truncated_mode, rsp->truncated_to_mode))
+ {
+ rsp->truncated_to_mode = truncated_mode;
+ rsp->truncation_label = label_tick;
+ }
+
+ return true;
+}
+
+/* Callback for note_uses. Find hardregs and subregs of pseudos and
+ the modes they are used in. This can help truning TRUNCATEs into
+ SUBREGs. */
+
+static void
+record_truncated_values (rtx *loc, void *data ATTRIBUTE_UNUSED)
+{
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, *loc, NONCONST)
+ if (record_truncated_value (*iter))
+ iter.skip_subrtxes ();
+}
+
+/* Scan X for promoted SUBREGs. For each one found,
+ note what it implies to the registers used in it. */
+
+static void
+check_promoted_subreg (rtx_insn *insn, rtx x)
+{
+ if (GET_CODE (x) == SUBREG
+ && SUBREG_PROMOTED_VAR_P (x)
+ && REG_P (SUBREG_REG (x)))
+ record_promoted_value (insn, x);
+ else
+ {
+ const char *format = GET_RTX_FORMAT (GET_CODE (x));
+ int i, j;
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+ switch (format[i])
+ {
+ case 'e':
+ check_promoted_subreg (insn, XEXP (x, i));
+ break;
+ case 'V':
+ case 'E':
+ if (XVEC (x, i) != 0)
+ for (j = 0; j < XVECLEN (x, i); j++)
+ check_promoted_subreg (insn, XVECEXP (x, i, j));
+ break;
+ }
+ }
+}
+
+/* Verify that all the registers and memory references mentioned in *LOC are
+ still valid. *LOC was part of a value set in INSN when label_tick was
+ equal to TICK. Return 0 if some are not. If REPLACE is nonzero, replace
+ the invalid references with (clobber (const_int 0)) and return 1. This
+ replacement is useful because we often can get useful information about
+ the form of a value (e.g., if it was produced by a shift that always
+ produces -1 or 0) even though we don't know exactly what registers it
+ was produced from. */
+
+static int
+get_last_value_validate (rtx *loc, rtx_insn *insn, int tick, int replace)
+{
+ rtx x = *loc;
+ const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
+ int len = GET_RTX_LENGTH (GET_CODE (x));
+ int i, j;
+
+ if (REG_P (x))
+ {
+ unsigned int regno = REGNO (x);
+ unsigned int endregno = END_REGNO (x);
+ unsigned int j;
+
+ for (j = regno; j < endregno; j++)
+ {
+ reg_stat_type *rsp = &reg_stat[j];
+ if (rsp->last_set_invalid
+ /* If this is a pseudo-register that was only set once and not
+ live at the beginning of the function, it is always valid. */
+ || (! (regno >= FIRST_PSEUDO_REGISTER
+ && regno < reg_n_sets_max
+ && REG_N_SETS (regno) == 1
+ && (!REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb),
+ regno)))
+ && rsp->last_set_label > tick))
+ {
+ if (replace)
+ *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ return replace;
+ }
+ }
+
+ return 1;
+ }
+ /* If this is a memory reference, make sure that there were no stores after
+ it that might have clobbered the value. We don't have alias info, so we
+ assume any store invalidates it. Moreover, we only have local UIDs, so
+ we also assume that there were stores in the intervening basic blocks. */
+ else if (MEM_P (x) && !MEM_READONLY_P (x)
+ && (tick != label_tick || DF_INSN_LUID (insn) <= mem_last_set))
+ {
+ if (replace)
+ *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ return replace;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ if (fmt[i] == 'e')
+ {
+ /* Check for identical subexpressions. If x contains
+ identical subexpression we only have to traverse one of
+ them. */
+ if (i == 1 && ARITHMETIC_P (x))
+ {
+ /* Note that at this point x0 has already been checked
+ and found valid. */
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ /* If x0 and x1 are identical then x is also valid. */
+ if (x0 == x1)
+ return 1;
+
+ /* If x1 is identical to a subexpression of x0 then
+ while checking x0, x1 has already been checked. Thus
+ it is valid and so as x. */
+ if (ARITHMETIC_P (x0)
+ && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+ return 1;
+
+ /* If x0 is identical to a subexpression of x1 then x is
+ valid iff the rest of x1 is valid. */
+ if (ARITHMETIC_P (x1)
+ && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+ return
+ get_last_value_validate (&XEXP (x1,
+ x0 == XEXP (x1, 0) ? 1 : 0),
+ insn, tick, replace);
+ }
+
+ if (get_last_value_validate (&XEXP (x, i), insn, tick,
+ replace) == 0)
+ return 0;
+ }
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (get_last_value_validate (&XVECEXP (x, i, j),
+ insn, tick, replace) == 0)
+ return 0;
+ }
+
+ /* If we haven't found a reason for it to be invalid, it is valid. */
+ return 1;
+}
+
+/* Get the last value assigned to X, if known. Some registers
+ in the value may be replaced with (clobber (const_int 0)) if their value
+ is known longer known reliably. */
+
+static rtx
+get_last_value (const_rtx x)
+{
+ unsigned int regno;
+ rtx value;
+ reg_stat_type *rsp;
+
+ /* If this is a non-paradoxical SUBREG, get the value of its operand and
+ then convert it to the desired mode. If this is a paradoxical SUBREG,
+ we cannot predict what values the "extra" bits might have. */
+ if (GET_CODE (x) == SUBREG
+ && subreg_lowpart_p (x)
+ && !paradoxical_subreg_p (x)
+ && (value = get_last_value (SUBREG_REG (x))) != 0)
+ return gen_lowpart (GET_MODE (x), value);
+
+ if (!REG_P (x))
+ return 0;
+
+ regno = REGNO (x);
+ rsp = &reg_stat[regno];
+ value = rsp->last_set_value;
+
+ /* If we don't have a value, or if it isn't for this basic block and
+ it's either a hard register, set more than once, or it's a live
+ at the beginning of the function, return 0.
+
+ Because if it's not live at the beginning of the function then the reg
+ is always set before being used (is never used without being set).
+ And, if it's set only once, and it's always set before use, then all
+ uses must have the same last value, even if it's not from this basic
+ block. */
+
+ if (value == 0
+ || (rsp->last_set_label < label_tick_ebb_start
+ && (regno < FIRST_PSEUDO_REGISTER
+ || regno >= reg_n_sets_max
+ || REG_N_SETS (regno) != 1
+ || REGNO_REG_SET_P
+ (DF_LR_IN (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb), regno))))
+ return 0;
+
+ /* If the value was set in a later insn than the ones we are processing,
+ we can't use it even if the register was only set once. */
+ if (rsp->last_set_label == label_tick
+ && DF_INSN_LUID (rsp->last_set) >= subst_low_luid)
+ return 0;
+
+ /* If fewer bits were set than what we are asked for now, we cannot use
+ the value. */
+ if (maybe_lt (GET_MODE_PRECISION (rsp->last_set_mode),
+ GET_MODE_PRECISION (GET_MODE (x))))
+ return 0;
+
+ /* If the value has all its registers valid, return it. */
+ if (get_last_value_validate (&value, rsp->last_set, rsp->last_set_label, 0))
+ return value;
+
+ /* Otherwise, make a copy and replace any invalid register with
+ (clobber (const_int 0)). If that fails for some reason, return 0. */
+
+ value = copy_rtx (value);
+ if (get_last_value_validate (&value, rsp->last_set, rsp->last_set_label, 1))
+ return value;
+
+ return 0;
+}
+
+/* Define three variables used for communication between the following
+ routines. */
+
+static unsigned int reg_dead_regno, reg_dead_endregno;
+static int reg_dead_flag;
+rtx reg_dead_reg;
+
+/* Function called via note_stores from reg_dead_at_p.
+
+ If DEST is within [reg_dead_regno, reg_dead_endregno), set
+ reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */
+
+static void
+reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
+{
+ unsigned int regno, endregno;
+
+ if (!REG_P (dest))
+ return;
+
+ regno = REGNO (dest);
+ endregno = END_REGNO (dest);
+ if (reg_dead_endregno > regno && reg_dead_regno < endregno)
+ reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1;
+}
+
+/* Return nonzero if REG is known to be dead at INSN.
+
+ We scan backwards from INSN. If we hit a REG_DEAD note or a CLOBBER
+ referencing REG, it is dead. If we hit a SET referencing REG, it is
+ live. Otherwise, see if it is live or dead at the start of the basic
+ block we are in. Hard regs marked as being live in NEWPAT_USED_REGS
+ must be assumed to be always live. */
+
+static int
+reg_dead_at_p (rtx reg, rtx_insn *insn)
+{
+ basic_block block;
+ unsigned int i;
+
+ /* Set variables for reg_dead_at_p_1. */
+ reg_dead_regno = REGNO (reg);
+ reg_dead_endregno = END_REGNO (reg);
+ reg_dead_reg = reg;
+
+ reg_dead_flag = 0;
+
+ /* Check that reg isn't mentioned in NEWPAT_USED_REGS. For fixed registers
+ we allow the machine description to decide whether use-and-clobber
+ patterns are OK. */
+ if (reg_dead_regno < FIRST_PSEUDO_REGISTER)
+ {
+ for (i = reg_dead_regno; i < reg_dead_endregno; i++)
+ if (!fixed_regs[i] && TEST_HARD_REG_BIT (newpat_used_regs, i))
+ return 0;
+ }
+
+ /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, or
+ beginning of basic block. */
+ block = BLOCK_FOR_INSN (insn);
+ for (;;)
+ {
+ if (INSN_P (insn))
+ {
+ if (find_regno_note (insn, REG_UNUSED, reg_dead_regno))
+ return 1;
+
+ note_stores (insn, reg_dead_at_p_1, NULL);
+ if (reg_dead_flag)
+ return reg_dead_flag == 1 ? 1 : 0;
+
+ if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
+ return 1;
+ }
+
+ if (insn == BB_HEAD (block))
+ break;
+
+ insn = PREV_INSN (insn);
+ }
+
+ /* Look at live-in sets for the basic block that we were in. */
+ for (i = reg_dead_regno; i < reg_dead_endregno; i++)
+ if (REGNO_REG_SET_P (df_get_live_in (block), i))
+ return 0;
+
+ return 1;
+}
+
+/* Note hard registers in X that are used. */
+
+static void
+mark_used_regs_combine (rtx x)
+{
+ RTX_CODE code = GET_CODE (x);
+ unsigned int regno;
+ int i;
+
+ switch (code)
+ {
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST:
+ CASE_CONST_ANY:
+ case PC:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case ASM_INPUT:
+ return;
+
+ case CLOBBER:
+ /* If we are clobbering a MEM, mark any hard registers inside the
+ address as used. */
+ if (MEM_P (XEXP (x, 0)))
+ mark_used_regs_combine (XEXP (XEXP (x, 0), 0));
+ return;
+
+ case REG:
+ regno = REGNO (x);
+ /* A hard reg in a wide mode may really be multiple registers.
+ If so, mark all of them just like the first. */
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ /* None of this applies to the stack, frame or arg pointers. */
+ if (regno == STACK_POINTER_REGNUM
+ || (!HARD_FRAME_POINTER_IS_FRAME_POINTER
+ && regno == HARD_FRAME_POINTER_REGNUM)
+ || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+ || regno == FRAME_POINTER_REGNUM)
+ return;
+
+ add_to_hard_reg_set (&newpat_used_regs, GET_MODE (x), regno);
+ }
+ return;
+
+ case SET:
+ {
+ /* If setting a MEM, or a SUBREG of a MEM, then note any hard regs in
+ the address. */
+ rtx testreg = SET_DEST (x);
+
+ while (GET_CODE (testreg) == SUBREG
+ || GET_CODE (testreg) == ZERO_EXTRACT
+ || GET_CODE (testreg) == STRICT_LOW_PART)
+ testreg = XEXP (testreg, 0);
+
+ if (MEM_P (testreg))
+ mark_used_regs_combine (XEXP (testreg, 0));
+
+ mark_used_regs_combine (SET_SRC (x));
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ /* Recursively scan the operands of this expression. */
+
+ {
+ const char *fmt = GET_RTX_FORMAT (code);
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ mark_used_regs_combine (XEXP (x, i));
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = 0; j < XVECLEN (x, i); j++)
+ mark_used_regs_combine (XVECEXP (x, i, j));
+ }
+ }
+ }
+}
+
+/* Remove register number REGNO from the dead registers list of INSN.
+
+ Return the note used to record the death, if there was one. */
+
+rtx
+remove_death (unsigned int regno, rtx_insn *insn)
+{
+ rtx note = find_regno_note (insn, REG_DEAD, regno);
+
+ if (note)
+ remove_note (insn, note);
+
+ return note;
+}
+
+/* For each register (hardware or pseudo) used within expression X, if its
+ death is in an instruction with luid between FROM_LUID (inclusive) and
+ TO_INSN (exclusive), put a REG_DEAD note for that register in the
+ list headed by PNOTES.
+
+ That said, don't move registers killed by maybe_kill_insn.
+
+ This is done when X is being merged by combination into TO_INSN. These
+ notes will then be distributed as needed. */
+
+static void
+move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
+ rtx *pnotes)
+{
+ const char *fmt;
+ int len, i;
+ enum rtx_code code = GET_CODE (x);
+
+ if (code == REG)
+ {
+ unsigned int regno = REGNO (x);
+ rtx_insn *where_dead = reg_stat[regno].last_death;
+
+ /* If we do not know where the register died, it may still die between
+ FROM_LUID and TO_INSN. If so, find it. This is PR83304. */
+ if (!where_dead || DF_INSN_LUID (where_dead) >= DF_INSN_LUID (to_insn))
+ {
+ rtx_insn *insn = prev_real_nondebug_insn (to_insn);
+ while (insn
+ && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (to_insn)
+ && DF_INSN_LUID (insn) >= from_luid)
+ {
+ if (dead_or_set_regno_p (insn, regno))
+ {
+ if (find_regno_note (insn, REG_DEAD, regno))
+ where_dead = insn;
+ break;
+ }
+
+ insn = prev_real_nondebug_insn (insn);
+ }
+ }
+
+ /* Don't move the register if it gets killed in between from and to. */
+ if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
+ && ! reg_referenced_p (x, maybe_kill_insn))
+ return;
+
+ if (where_dead
+ && BLOCK_FOR_INSN (where_dead) == BLOCK_FOR_INSN (to_insn)
+ && DF_INSN_LUID (where_dead) >= from_luid
+ && DF_INSN_LUID (where_dead) < DF_INSN_LUID (to_insn))
+ {
+ rtx note = remove_death (regno, where_dead);
+
+ /* It is possible for the call above to return 0. This can occur
+ when last_death points to I2 or I1 that we combined with.
+ In that case make a new note.
+
+ We must also check for the case where X is a hard register
+ and NOTE is a death note for a range of hard registers
+ including X. In that case, we must put REG_DEAD notes for
+ the remaining registers in place of NOTE. */
+
+ if (note != 0 && regno < FIRST_PSEUDO_REGISTER
+ && partial_subreg_p (GET_MODE (x), GET_MODE (XEXP (note, 0))))
+ {
+ unsigned int deadregno = REGNO (XEXP (note, 0));
+ unsigned int deadend = END_REGNO (XEXP (note, 0));
+ unsigned int ourend = END_REGNO (x);
+ unsigned int i;
+
+ for (i = deadregno; i < deadend; i++)
+ if (i < regno || i >= ourend)
+ add_reg_note (where_dead, REG_DEAD, regno_reg_rtx[i]);
+ }
+
+ /* If we didn't find any note, or if we found a REG_DEAD note that
+ covers only part of the given reg, and we have a multi-reg hard
+ register, then to be safe we must check for REG_DEAD notes
+ for each register other than the first. They could have
+ their own REG_DEAD notes lying around. */
+ else if ((note == 0
+ || (note != 0
+ && partial_subreg_p (GET_MODE (XEXP (note, 0)),
+ GET_MODE (x))))
+ && regno < FIRST_PSEUDO_REGISTER
+ && REG_NREGS (x) > 1)
+ {
+ unsigned int ourend = END_REGNO (x);
+ unsigned int i, offset;
+ rtx oldnotes = 0;
+
+ if (note)
+ offset = hard_regno_nregs (regno, GET_MODE (XEXP (note, 0)));
+ else
+ offset = 1;
+
+ for (i = regno + offset; i < ourend; i++)
+ move_deaths (regno_reg_rtx[i],
+ maybe_kill_insn, from_luid, to_insn, &oldnotes);
+ }
+
+ if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
+ {
+ XEXP (note, 1) = *pnotes;
+ *pnotes = note;
+ }
+ else
+ *pnotes = alloc_reg_note (REG_DEAD, x, *pnotes);
+ }
+
+ return;
+ }
+
+ else if (GET_CODE (x) == SET)
+ {
+ rtx dest = SET_DEST (x);
+
+ move_deaths (SET_SRC (x), maybe_kill_insn, from_luid, to_insn, pnotes);
+
+ /* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG
+ that accesses one word of a multi-word item, some
+ piece of everything register in the expression is used by
+ this insn, so remove any old death. */
+ /* ??? So why do we test for equality of the sizes? */
+
+ if (GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART
+ || (GET_CODE (dest) == SUBREG
+ && !read_modify_subreg_p (dest)))
+ {
+ move_deaths (dest, maybe_kill_insn, from_luid, to_insn, pnotes);
+ return;
+ }
+
+ /* If this is some other SUBREG, we know it replaces the entire
+ value, so use that as the destination. */
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ /* If this is a MEM, adjust deaths of anything used in the address.
+ For a REG (the only other possibility), the entire value is
+ being replaced so the old value is not used in this insn. */
+
+ if (MEM_P (dest))
+ move_deaths (XEXP (dest, 0), maybe_kill_insn, from_luid,
+ to_insn, pnotes);
+ return;
+ }
+
+ else if (GET_CODE (x) == CLOBBER)
+ return;
+
+ len = GET_RTX_LENGTH (code);
+ fmt = GET_RTX_FORMAT (code);
+
+ for (i = 0; i < len; i++)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_luid,
+ to_insn, pnotes);
+ }
+ else if (fmt[i] == 'e')
+ move_deaths (XEXP (x, i), maybe_kill_insn, from_luid, to_insn, pnotes);
+ }
+}
+
+/* Return 1 if X is the target of a bit-field assignment in BODY, the
+ pattern of an insn. X must be a REG. */
+
+static int
+reg_bitfield_target_p (rtx x, rtx body)
+{
+ int i;
+
+ if (GET_CODE (body) == SET)
+ {
+ rtx dest = SET_DEST (body);
+ rtx target;
+ unsigned int regno, tregno, endregno, endtregno;
+
+ if (GET_CODE (dest) == ZERO_EXTRACT)
+ target = XEXP (dest, 0);
+ else if (GET_CODE (dest) == STRICT_LOW_PART)
+ target = SUBREG_REG (XEXP (dest, 0));
+ else
+ return 0;
+
+ if (GET_CODE (target) == SUBREG)
+ target = SUBREG_REG (target);
+
+ if (!REG_P (target))
+ return 0;
+
+ tregno = REGNO (target), regno = REGNO (x);
+ if (tregno >= FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER)
+ return target == x;
+
+ endtregno = end_hard_regno (GET_MODE (target), tregno);
+ endregno = end_hard_regno (GET_MODE (x), regno);
+
+ return endregno > tregno && regno < endtregno;
+ }
+
+ else if (GET_CODE (body) == PARALLEL)
+ for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+ if (reg_bitfield_target_p (x, XVECEXP (body, 0, i)))
+ return 1;
+
+ return 0;
+}
+
+/* Given a chain of REG_NOTES originally from FROM_INSN, try to place them
+ as appropriate. I3 and I2 are the insns resulting from the combination
+ insns including FROM (I2 may be zero).
+
+ ELIM_I2 and ELIM_I1 are either zero or registers that we know will
+ not need REG_DEAD notes because they are being substituted for. This
+ saves searching in the most common cases.
+
+ Each note in the list is either ignored or placed on some insns, depending
+ on the type of note. */
+
+static void
+distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
+ rtx elim_i2, rtx elim_i1, rtx elim_i0)
+{
+ rtx note, next_note;
+ rtx tem_note;
+ rtx_insn *tem_insn;
+
+ for (note = notes; note; note = next_note)
+ {
+ rtx_insn *place = 0, *place2 = 0;
+
+ next_note = XEXP (note, 1);
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_BR_PROB:
+ case REG_BR_PRED:
+ /* Doesn't matter much where we put this, as long as it's somewhere.
+ It is preferable to keep these notes on branches, which is most
+ likely to be i3. */
+ place = i3;
+ break;
+
+ case REG_NON_LOCAL_GOTO:
+ if (JUMP_P (i3))
+ place = i3;
+ else
+ {
+ gcc_assert (i2 && JUMP_P (i2));
+ place = i2;
+ }
+ break;
+
+ case REG_EH_REGION:
+ /* These notes must remain with the call or trapping instruction. */
+ if (CALL_P (i3))
+ place = i3;
+ else if (i2 && CALL_P (i2))
+ place = i2;
+ else
+ {
+ gcc_assert (cfun->can_throw_non_call_exceptions);
+ if (may_trap_p (i3))
+ place = i3;
+ else if (i2 && may_trap_p (i2))
+ place = i2;
+ /* ??? Otherwise assume we've combined things such that we
+ can now prove that the instructions can't trap. Drop the
+ note in this case. */
+ }
+ break;
+
+ case REG_ARGS_SIZE:
+ /* ??? How to distribute between i3-i1. Assume i3 contains the
+ entire adjustment. Assert i3 contains at least some adjust. */
+ if (!noop_move_p (i3))
+ {
+ poly_int64 old_size, args_size = get_args_size (note);
+ /* fixup_args_size_notes looks at REG_NORETURN note,
+ so ensure the note is placed there first. */
+ if (CALL_P (i3))
+ {
+ rtx *np;
+ for (np = &next_note; *np; np = &XEXP (*np, 1))
+ if (REG_NOTE_KIND (*np) == REG_NORETURN)
+ {
+ rtx n = *np;
+ *np = XEXP (n, 1);
+ XEXP (n, 1) = REG_NOTES (i3);
+ REG_NOTES (i3) = n;
+ break;
+ }
+ }
+ old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
+ /* emit_call_1 adds for !ACCUMULATE_OUTGOING_ARGS
+ REG_ARGS_SIZE note to all noreturn calls, allow that here. */
+ gcc_assert (maybe_ne (old_size, args_size)
+ || (CALL_P (i3)
+ && !ACCUMULATE_OUTGOING_ARGS
+ && find_reg_note (i3, REG_NORETURN, NULL_RTX)));
+ }
+ break;
+
+ case REG_NORETURN:
+ case REG_SETJMP:
+ case REG_TM:
+ case REG_CALL_DECL:
+ case REG_UNTYPED_CALL:
+ case REG_CALL_NOCF_CHECK:
+ /* These notes must remain with the call. It should not be
+ possible for both I2 and I3 to be a call. */
+ if (CALL_P (i3))
+ place = i3;
+ else
+ {
+ gcc_assert (i2 && CALL_P (i2));
+ place = i2;
+ }
+ break;
+
+ case REG_UNUSED:
+ /* Any clobbers for i3 may still exist, and so we must process
+ REG_UNUSED notes from that insn.
+
+ Any clobbers from i2 or i1 can only exist if they were added by
+ recog_for_combine. In that case, recog_for_combine created the
+ necessary REG_UNUSED notes. Trying to keep any original
+ REG_UNUSED notes from these insns can cause incorrect output
+ if it is for the same register as the original i3 dest.
+ In that case, we will notice that the register is set in i3,
+ and then add a REG_UNUSED note for the destination of i3, which
+ is wrong. However, it is possible to have REG_UNUSED notes from
+ i2 or i1 for register which were both used and clobbered, so
+ we keep notes from i2 or i1 if they will turn into REG_DEAD
+ notes. */
+
+ /* If this register is set or clobbered between FROM_INSN and I3,
+ we should not create a note for it. */
+ if (reg_set_between_p (XEXP (note, 0), from_insn, i3))
+ break;
+
+ /* If this register is set or clobbered in I3, put the note there
+ unless there is one already. */
+ if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
+ {
+ if (from_insn != i3)
+ break;
+
+ if (! (REG_P (XEXP (note, 0))
+ ? find_regno_note (i3, REG_UNUSED, REGNO (XEXP (note, 0)))
+ : find_reg_note (i3, REG_UNUSED, XEXP (note, 0))))
+ place = i3;
+ }
+ /* Otherwise, if this register is used by I3, then this register
+ now dies here, so we must put a REG_DEAD note here unless there
+ is one already. */
+ else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))
+ && ! (REG_P (XEXP (note, 0))
+ ? find_regno_note (i3, REG_DEAD,
+ REGNO (XEXP (note, 0)))
+ : find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
+ {
+ PUT_REG_NOTE_KIND (note, REG_DEAD);
+ place = i3;
+ }
+
+ /* A SET or CLOBBER of the REG_UNUSED reg has been removed,
+ but we can't tell which at this point. We must reset any
+ expectations we had about the value that was previously
+ stored in the reg. ??? Ideally, we'd adjust REG_N_SETS
+ and, if appropriate, restore its previous value, but we
+ don't have enough information for that at this point. */
+ else
+ {
+ record_value_for_reg (XEXP (note, 0), NULL, NULL_RTX);
+
+ /* Otherwise, if this register is now referenced in i2
+ then the register used to be modified in one of the
+ original insns. If it was i3 (say, in an unused
+ parallel), it's now completely gone, so the note can
+ be discarded. But if it was modified in i2, i1 or i0
+ and we still reference it in i2, then we're
+ referencing the previous value, and since the
+ register was modified and REG_UNUSED, we know that
+ the previous value is now dead. So, if we only
+ reference the register in i2, we change the note to
+ REG_DEAD, to reflect the previous value. However, if
+ we're also setting or clobbering the register as
+ scratch, we know (because the register was not
+ referenced in i3) that it's unused, just as it was
+ unused before, and we place the note in i2. */
+ if (from_insn != i3 && i2 && INSN_P (i2)
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ if (!reg_set_p (XEXP (note, 0), PATTERN (i2)))
+ PUT_REG_NOTE_KIND (note, REG_DEAD);
+ if (! (REG_P (XEXP (note, 0))
+ ? find_regno_note (i2, REG_NOTE_KIND (note),
+ REGNO (XEXP (note, 0)))
+ : find_reg_note (i2, REG_NOTE_KIND (note),
+ XEXP (note, 0))))
+ place = i2;
+ }
+ }
+
+ break;
+
+ case REG_EQUAL:
+ case REG_EQUIV:
+ case REG_NOALIAS:
+ /* These notes say something about results of an insn. We can
+ only support them if they used to be on I3 in which case they
+ remain on I3. Otherwise they are ignored.
+
+ If the note refers to an expression that is not a constant, we
+ must also ignore the note since we cannot tell whether the
+ equivalence is still true. It might be possible to do
+ slightly better than this (we only have a problem if I2DEST
+ or I1DEST is present in the expression), but it doesn't
+ seem worth the trouble. */
+
+ if (from_insn == i3
+ && (XEXP (note, 0) == 0 || CONSTANT_P (XEXP (note, 0))))
+ place = i3;
+ break;
+
+ case REG_INC:
+ /* These notes say something about how a register is used. They must
+ be present on any use of the register in I2 or I3. */
+ if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3)))
+ place = i3;
+
+ if (i2 && reg_mentioned_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ if (place)
+ place2 = i2;
+ else
+ place = i2;
+ }
+ break;
+
+ case REG_LABEL_TARGET:
+ case REG_LABEL_OPERAND:
+ /* This can show up in several ways -- either directly in the
+ pattern, or hidden off in the constant pool with (or without?)
+ a REG_EQUAL note. */
+ /* ??? Ignore the without-reg_equal-note problem for now. */
+ if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3))
+ || ((tem_note = find_reg_note (i3, REG_EQUAL, NULL_RTX))
+ && GET_CODE (XEXP (tem_note, 0)) == LABEL_REF
+ && label_ref_label (XEXP (tem_note, 0)) == XEXP (note, 0)))
+ place = i3;
+
+ if (i2
+ && (reg_mentioned_p (XEXP (note, 0), PATTERN (i2))
+ || ((tem_note = find_reg_note (i2, REG_EQUAL, NULL_RTX))
+ && GET_CODE (XEXP (tem_note, 0)) == LABEL_REF
+ && label_ref_label (XEXP (tem_note, 0)) == XEXP (note, 0))))
+ {
+ if (place)
+ place2 = i2;
+ else
+ place = i2;
+ }
+
+ /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+ as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+ there. */
+ if (place && JUMP_P (place)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place) == NULL
+ || JUMP_LABEL (place) == XEXP (note, 0)))
+ {
+ rtx label = JUMP_LABEL (place);
+
+ if (!label)
+ JUMP_LABEL (place) = XEXP (note, 0);
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
+ }
+
+ if (place2 && JUMP_P (place2)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place2) == NULL
+ || JUMP_LABEL (place2) == XEXP (note, 0)))
+ {
+ rtx label = JUMP_LABEL (place2);
+
+ if (!label)
+ JUMP_LABEL (place2) = XEXP (note, 0);
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
+ place2 = 0;
+ }
+ break;
+
+ case REG_NONNEG:
+ /* This note says something about the value of a register prior
+ to the execution of an insn. It is too much trouble to see
+ if the note is still correct in all situations. It is better
+ to simply delete it. */
+ break;
+
+ case REG_DEAD:
+ /* If we replaced the right hand side of FROM_INSN with a
+ REG_EQUAL note, the original use of the dying register
+ will not have been combined into I3 and I2. In such cases,
+ FROM_INSN is guaranteed to be the first of the combined
+ instructions, so we simply need to search back before
+ FROM_INSN for the previous use or set of this register,
+ then alter the notes there appropriately.
+
+ If the register is used as an input in I3, it dies there.
+ Similarly for I2, if it is nonzero and adjacent to I3.
+
+ If the register is not used as an input in either I3 or I2
+ and it is not one of the registers we were supposed to eliminate,
+ there are two possibilities. We might have a non-adjacent I2
+ or we might have somehow eliminated an additional register
+ from a computation. For example, we might have had A & B where
+ we discover that B will always be zero. In this case we will
+ eliminate the reference to A.
+
+ In both cases, we must search to see if we can find a previous
+ use of A and put the death note there. */
+
+ if (from_insn
+ && from_insn == i2mod
+ && !reg_overlap_mentioned_p (XEXP (note, 0), i2mod_new_rhs))
+ tem_insn = from_insn;
+ else
+ {
+ if (from_insn
+ && CALL_P (from_insn)
+ && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
+ place = from_insn;
+ else if (i2 && reg_set_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ /* If the new I2 sets the same register that is marked
+ dead in the note, we do not in general know where to
+ put the note. One important case we _can_ handle is
+ when the note comes from I3. */
+ if (from_insn == i3)
+ place = i3;
+ else
+ break;
+ }
+ else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
+ place = i3;
+ else if (i2 != 0 && next_nonnote_nondebug_insn (i2) == i3
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ place = i2;
+ else if ((rtx_equal_p (XEXP (note, 0), elim_i2)
+ && !(i2mod
+ && reg_overlap_mentioned_p (XEXP (note, 0),
+ i2mod_old_rhs)))
+ || rtx_equal_p (XEXP (note, 0), elim_i1)
+ || rtx_equal_p (XEXP (note, 0), elim_i0))
+ break;
+ tem_insn = i3;
+ }
+
+ if (place == 0)
+ {
+ basic_block bb = this_basic_block;
+
+ for (tem_insn = PREV_INSN (tem_insn); place == 0; tem_insn = PREV_INSN (tem_insn))
+ {
+ if (!NONDEBUG_INSN_P (tem_insn))
+ {
+ if (tem_insn == BB_HEAD (bb))
+ break;
+ continue;
+ }
+
+ /* If the register is being set at TEM_INSN, see if that is all
+ TEM_INSN is doing. If so, delete TEM_INSN. Otherwise, make this
+ into a REG_UNUSED note instead. Don't delete sets to
+ global register vars. */
+ if ((REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER
+ || !global_regs[REGNO (XEXP (note, 0))])
+ && reg_set_p (XEXP (note, 0), PATTERN (tem_insn)))
+ {
+ rtx set = single_set (tem_insn);
+ rtx inner_dest = 0;
+
+ if (set != 0)
+ for (inner_dest = SET_DEST (set);
+ (GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT);
+ inner_dest = XEXP (inner_dest, 0))
+ ;
+
+ /* Verify that it was the set, and not a clobber that
+ modified the register.
+
+ If we cannot delete the setter due to side
+ effects, mark the user with an UNUSED note instead
+ of deleting it. */
+
+ if (set != 0 && ! side_effects_p (SET_SRC (set))
+ && rtx_equal_p (XEXP (note, 0), inner_dest))
+ {
+ /* Move the notes and links of TEM_INSN elsewhere.
+ This might delete other dead insns recursively.
+ First set the pattern to something that won't use
+ any register. */
+ rtx old_notes = REG_NOTES (tem_insn);
+
+ PATTERN (tem_insn) = pc_rtx;
+ REG_NOTES (tem_insn) = NULL;
+
+ distribute_notes (old_notes, tem_insn, tem_insn, NULL,
+ NULL_RTX, NULL_RTX, NULL_RTX);
+ distribute_links (LOG_LINKS (tem_insn));
+
+ unsigned int regno = REGNO (XEXP (note, 0));
+ reg_stat_type *rsp = &reg_stat[regno];
+ if (rsp->last_set == tem_insn)
+ record_value_for_reg (XEXP (note, 0), NULL, NULL_RTX);
+
+ SET_INSN_DELETED (tem_insn);
+ if (tem_insn == i2)
+ i2 = NULL;
+ }
+ else
+ {
+ PUT_REG_NOTE_KIND (note, REG_UNUSED);
+
+ /* If there isn't already a REG_UNUSED note, put one
+ here. Do not place a REG_DEAD note, even if
+ the register is also used here; that would not
+ match the algorithm used in lifetime analysis
+ and can cause the consistency check in the
+ scheduler to fail. */
+ if (! find_regno_note (tem_insn, REG_UNUSED,
+ REGNO (XEXP (note, 0))))
+ place = tem_insn;
+ break;
+ }
+ }
+ else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem_insn))
+ || (CALL_P (tem_insn)
+ && find_reg_fusage (tem_insn, USE, XEXP (note, 0))))
+ {
+ place = tem_insn;
+
+ /* If we are doing a 3->2 combination, and we have a
+ register which formerly died in i3 and was not used
+ by i2, which now no longer dies in i3 and is used in
+ i2 but does not die in i2, and place is between i2
+ and i3, then we may need to move a link from place to
+ i2. */
+ if (i2 && DF_INSN_LUID (place) > DF_INSN_LUID (i2)
+ && from_insn
+ && DF_INSN_LUID (from_insn) > DF_INSN_LUID (i2)
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ struct insn_link *links = LOG_LINKS (place);
+ LOG_LINKS (place) = NULL;
+ distribute_links (links);
+ }
+ break;
+ }
+
+ if (tem_insn == BB_HEAD (bb))
+ break;
+ }
+
+ }
+
+ /* If the register is set or already dead at PLACE, we needn't do
+ anything with this note if it is still a REG_DEAD note.
+ We check here if it is set at all, not if is it totally replaced,
+ which is what `dead_or_set_p' checks, so also check for it being
+ set partially. */
+
+ if (place && REG_NOTE_KIND (note) == REG_DEAD)
+ {
+ unsigned int regno = REGNO (XEXP (note, 0));
+ reg_stat_type *rsp = &reg_stat[regno];
+
+ if (dead_or_set_p (place, XEXP (note, 0))
+ || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
+ {
+ /* Unless the register previously died in PLACE, clear
+ last_death. [I no longer understand why this is
+ being done.] */
+ if (rsp->last_death != place)
+ rsp->last_death = 0;
+ place = 0;
+ }
+ else
+ rsp->last_death = place;
+
+ /* If this is a death note for a hard reg that is occupying
+ multiple registers, ensure that we are still using all
+ parts of the object. If we find a piece of the object
+ that is unused, we must arrange for an appropriate REG_DEAD
+ note to be added for it. However, we can't just emit a USE
+ and tag the note to it, since the register might actually
+ be dead; so we recourse, and the recursive call then finds
+ the previous insn that used this register. */
+
+ if (place && REG_NREGS (XEXP (note, 0)) > 1)
+ {
+ unsigned int endregno = END_REGNO (XEXP (note, 0));
+ bool all_used = true;
+ unsigned int i;
+
+ for (i = regno; i < endregno; i++)
+ if ((! refers_to_regno_p (i, PATTERN (place))
+ && ! find_regno_fusage (place, USE, i))
+ || dead_or_set_regno_p (place, i))
+ {
+ all_used = false;
+ break;
+ }
+
+ if (! all_used)
+ {
+ /* Put only REG_DEAD notes for pieces that are
+ not already dead or set. */
+
+ for (i = regno; i < endregno;
+ i += hard_regno_nregs (i, reg_raw_mode[i]))
+ {
+ rtx piece = regno_reg_rtx[i];
+ basic_block bb = this_basic_block;
+
+ if (! dead_or_set_p (place, piece)
+ && ! reg_bitfield_target_p (piece,
+ PATTERN (place)))
+ {
+ rtx new_note = alloc_reg_note (REG_DEAD, piece,
+ NULL_RTX);
+
+ distribute_notes (new_note, place, place,
+ NULL, NULL_RTX, NULL_RTX,
+ NULL_RTX);
+ }
+ else if (! refers_to_regno_p (i, PATTERN (place))
+ && ! find_regno_fusage (place, USE, i))
+ for (tem_insn = PREV_INSN (place); ;
+ tem_insn = PREV_INSN (tem_insn))
+ {
+ if (!NONDEBUG_INSN_P (tem_insn))
+ {
+ if (tem_insn == BB_HEAD (bb))
+ break;
+ continue;
+ }
+ if (dead_or_set_p (tem_insn, piece)
+ || reg_bitfield_target_p (piece,
+ PATTERN (tem_insn)))
+ {
+ add_reg_note (tem_insn, REG_UNUSED, piece);
+ break;
+ }
+ }
+ }
+
+ place = 0;
+ }
+ }
+ }
+ break;
+
+ default:
+ /* Any other notes should not be present at this point in the
+ compilation. */
+ gcc_unreachable ();
+ }
+
+ if (place)
+ {
+ XEXP (note, 1) = REG_NOTES (place);
+ REG_NOTES (place) = note;
+
+ /* Set added_notes_insn to the earliest insn we added a note to. */
+ if (added_notes_insn == 0
+ || DF_INSN_LUID (added_notes_insn) > DF_INSN_LUID (place))
+ added_notes_insn = place;
+ }
+
+ if (place2)
+ {
+ add_shallow_copy_of_reg_note (place2, note);
+
+ /* Set added_notes_insn to the earliest insn we added a note to. */
+ if (added_notes_insn == 0
+ || DF_INSN_LUID (added_notes_insn) > DF_INSN_LUID (place2))
+ added_notes_insn = place2;
+ }
+ }
+}
+
+/* Similarly to above, distribute the LOG_LINKS that used to be present on
+ I3, I2, and I1 to new locations. This is also called to add a link
+ pointing at I3 when I3's destination is changed. */
+
+static void
+distribute_links (struct insn_link *links)
+{
+ struct insn_link *link, *next_link;
+
+ for (link = links; link; link = next_link)
+ {
+ rtx_insn *place = 0;
+ rtx_insn *insn;
+ rtx set, reg;
+
+ next_link = link->next;
+
+ /* If the insn that this link points to is a NOTE, ignore it. */
+ if (NOTE_P (link->insn))
+ continue;
+
+ set = 0;
+ rtx pat = PATTERN (link->insn);
+ if (GET_CODE (pat) == SET)
+ set = pat;
+ else if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ set = XVECEXP (pat, 0, i);
+ if (GET_CODE (set) != SET)
+ continue;
+
+ reg = SET_DEST (set);
+ while (GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART
+ || GET_CODE (reg) == SUBREG)
+ reg = XEXP (reg, 0);
+
+ if (!REG_P (reg))
+ continue;
+
+ if (REGNO (reg) == link->regno)
+ break;
+ }
+ if (i == XVECLEN (pat, 0))
+ continue;
+ }
+ else
+ continue;
+
+ reg = SET_DEST (set);
+
+ while (GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART
+ || GET_CODE (reg) == SUBREG)
+ reg = XEXP (reg, 0);
+
+ if (reg == pc_rtx)
+ continue;
+
+ /* A LOG_LINK is defined as being placed on the first insn that uses
+ a register and points to the insn that sets the register. Start
+ searching at the next insn after the target of the link and stop
+ when we reach a set of the register or the end of the basic block.
+
+ Note that this correctly handles the link that used to point from
+ I3 to I2. Also note that not much searching is typically done here
+ since most links don't point very far away. */
+
+ for (insn = NEXT_INSN (link->insn);
+ (insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
+ || BB_HEAD (this_basic_block->next_bb) != insn));
+ insn = NEXT_INSN (insn))
+ if (DEBUG_INSN_P (insn))
+ continue;
+ else if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+ {
+ if (reg_referenced_p (reg, PATTERN (insn)))
+ place = insn;
+ break;
+ }
+ else if (CALL_P (insn)
+ && find_reg_fusage (insn, USE, reg))
+ {
+ place = insn;
+ break;
+ }
+ else if (INSN_P (insn) && reg_set_p (reg, insn))
+ break;
+
+ /* If we found a place to put the link, place it there unless there
+ is already a link to the same insn as LINK at that point. */
+
+ if (place)
+ {
+ struct insn_link *link2;
+
+ FOR_EACH_LOG_LINK (link2, place)
+ if (link2->insn == link->insn && link2->regno == link->regno)
+ break;
+
+ if (link2 == NULL)
+ {
+ link->next = LOG_LINKS (place);
+ LOG_LINKS (place) = link;
+
+ /* Set added_links_insn to the earliest insn we added a
+ link to. */
+ if (added_links_insn == 0
+ || DF_INSN_LUID (added_links_insn) > DF_INSN_LUID (place))
+ added_links_insn = place;
+ }
+ }
+ }
+}
+
+/* Check for any register or memory mentioned in EQUIV that is not
+ mentioned in EXPR. This is used to restrict EQUIV to "specializations"
+ of EXPR where some registers may have been replaced by constants. */
+
+static bool
+unmentioned_reg_p (rtx equiv, rtx expr)
+{
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, equiv, NONCONST)
+ {
+ const_rtx x = *iter;
+ if ((REG_P (x) || MEM_P (x))
+ && !reg_mentioned_p (x, expr))
+ return true;
+ }
+ return false;
+}
+
+DEBUG_FUNCTION void
+dump_combine_stats (FILE *file)
+{
+ fprintf
+ (file,
+ ";; Combiner statistics: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n\n",
+ combine_attempts, combine_merges, combine_extras, combine_successes);
+}
+
+void
+dump_combine_total_stats (FILE *file)
+{
+ fprintf
+ (file,
+ "\n;; Combiner totals: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n",
+ total_attempts, total_merges, total_extras, total_successes);
+}
+
+/* Make pseudo-to-pseudo copies after every hard-reg-to-pseudo-copy, because
+ the reg-to-reg copy can usefully combine with later instructions, but we
+ do not want to combine the hard reg into later instructions, for that
+ restricts register allocation. */
+static void
+make_more_copies (void)
+{
+ basic_block bb;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ rtx_insn *insn;
+
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ rtx set = single_set (insn);
+ if (!set)
+ continue;
+
+ rtx dest = SET_DEST (set);
+ if (!(REG_P (dest) && !HARD_REGISTER_P (dest)))
+ continue;
+
+ rtx src = SET_SRC (set);
+ if (!(REG_P (src) && HARD_REGISTER_P (src)))
+ continue;
+ if (TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src)))
+ continue;
+
+ rtx new_reg = gen_reg_rtx (GET_MODE (dest));
+ rtx_insn *new_insn = gen_move_insn (new_reg, src);
+ SET_SRC (set) = new_reg;
+ emit_insn_before (new_insn, insn);
+ df_insn_rescan (insn);
+ }
+ }
+}
+
+/* Try combining insns through substitution. */
+static unsigned int
+rest_of_handle_combine (void)
+{
+ make_more_copies ();
+
+ df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
+ df_note_add_problem ();
+ df_analyze ();
+
+ regstat_init_n_sets_and_refs ();
+ reg_n_sets_max = max_reg_num ();
+
+ int rebuild_jump_labels_after_combine
+ = combine_instructions (get_insns (), max_reg_num ());
+
+ /* Combining insns may have turned an indirect jump into a
+ direct jump. Rebuild the JUMP_LABEL fields of jumping
+ instructions. */
+ if (rebuild_jump_labels_after_combine)
+ {
+ if (dom_info_available_p (CDI_DOMINATORS))
+ free_dominance_info (CDI_DOMINATORS);
+ timevar_push (TV_JUMP);
+ rebuild_jump_labels (get_insns ());
+ cleanup_cfg (0);
+ timevar_pop (TV_JUMP);
+ }
+
+ regstat_free_n_sets_and_refs ();
+ return 0;
+}
+
+namespace {
+
+const pass_data pass_data_combine =
+{
+ RTL_PASS, /* type */
+ "combine", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_COMBINE, /* tv_id */
+ PROP_cfglayout, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish, /* todo_flags_finish */
+};
+
+class pass_combine : public rtl_opt_pass
+{
+public:
+ pass_combine (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_combine, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return (optimize > 0); }
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_handle_combine ();
+ }
+
+}; // class pass_combine
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_combine (gcc::context *ctxt)
+{
+ return new pass_combine (ctxt);
+}