aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/tree-ssa-math-opts.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r--gcc/tree-ssa-math-opts.c5070
1 files changed, 0 insertions, 5070 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
deleted file mode 100644
index e3c3bd8..0000000
--- a/gcc/tree-ssa-math-opts.c
+++ /dev/null
@@ -1,5070 +0,0 @@
-/* Global, SSA-based optimizations using mathematical identities.
- Copyright (C) 2005-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/>. */
-
-/* Currently, the only mini-pass in this file tries to CSE reciprocal
- operations. These are common in sequences such as this one:
-
- modulus = sqrt(x*x + y*y + z*z);
- x = x / modulus;
- y = y / modulus;
- z = z / modulus;
-
- that can be optimized to
-
- modulus = sqrt(x*x + y*y + z*z);
- rmodulus = 1.0 / modulus;
- x = x * rmodulus;
- y = y * rmodulus;
- z = z * rmodulus;
-
- We do this for loop invariant divisors, and with this pass whenever
- we notice that a division has the same divisor multiple times.
-
- Of course, like in PRE, we don't insert a division if a dominator
- already has one. However, this cannot be done as an extension of
- PRE for several reasons.
-
- First of all, with some experiments it was found out that the
- transformation is not always useful if there are only two divisions
- by the same divisor. This is probably because modern processors
- can pipeline the divisions; on older, in-order processors it should
- still be effective to optimize two divisions by the same number.
- We make this a param, and it shall be called N in the remainder of
- this comment.
-
- Second, if trapping math is active, we have less freedom on where
- to insert divisions: we can only do so in basic blocks that already
- contain one. (If divisions don't trap, instead, we can insert
- divisions elsewhere, which will be in blocks that are common dominators
- of those that have the division).
-
- We really don't want to compute the reciprocal unless a division will
- be found. To do this, we won't insert the division in a basic block
- that has less than N divisions *post-dominating* it.
-
- The algorithm constructs a subset of the dominator tree, holding the
- blocks containing the divisions and the common dominators to them,
- and walk it twice. The first walk is in post-order, and it annotates
- each block with the number of divisions that post-dominate it: this
- gives information on where divisions can be inserted profitably.
- The second walk is in pre-order, and it inserts divisions as explained
- above, and replaces divisions by multiplications.
-
- In the best case, the cost of the pass is O(n_statements). In the
- worst-case, the cost is due to creating the dominator tree subset,
- with a cost of O(n_basic_blocks ^ 2); however this can only happen
- for n_statements / n_basic_blocks statements. So, the amortized cost
- of creating the dominator tree subset is O(n_basic_blocks) and the
- worst-case cost of the pass is O(n_statements * n_basic_blocks).
-
- More practically, the cost will be small because there are few
- divisions, and they tend to be in the same basic block, so insert_bb
- is called very few times.
-
- If we did this using domwalk.c, an efficient implementation would have
- to work on all the variables in a single pass, because we could not
- work on just a subset of the dominator tree, as we do now, and the
- cost would also be something like O(n_statements * n_basic_blocks).
- The data structures would be more complex in order to work on all the
- variables in a single pass. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "target.h"
-#include "rtl.h"
-#include "tree.h"
-#include "gimple.h"
-#include "predict.h"
-#include "alloc-pool.h"
-#include "tree-pass.h"
-#include "ssa.h"
-#include "optabs-tree.h"
-#include "gimple-pretty-print.h"
-#include "alias.h"
-#include "fold-const.h"
-#include "gimple-fold.h"
-#include "gimple-iterator.h"
-#include "gimplify.h"
-#include "gimplify-me.h"
-#include "stor-layout.h"
-#include "tree-cfg.h"
-#include "tree-dfa.h"
-#include "tree-ssa.h"
-#include "builtins.h"
-#include "internal-fn.h"
-#include "case-cfn-macros.h"
-#include "optabs-libfuncs.h"
-#include "tree-eh.h"
-#include "targhooks.h"
-#include "domwalk.h"
-#include "tree-ssa-math-opts.h"
-
-/* This structure represents one basic block that either computes a
- division, or is a common dominator for basic block that compute a
- division. */
-struct occurrence {
- /* The basic block represented by this structure. */
- basic_block bb = basic_block();
-
- /* If non-NULL, the SSA_NAME holding the definition for a reciprocal
- inserted in BB. */
- tree recip_def = tree();
-
- /* If non-NULL, the SSA_NAME holding the definition for a squared
- reciprocal inserted in BB. */
- tree square_recip_def = tree();
-
- /* If non-NULL, the GIMPLE_ASSIGN for a reciprocal computation that
- was inserted in BB. */
- gimple *recip_def_stmt = nullptr;
-
- /* Pointer to a list of "struct occurrence"s for blocks dominated
- by BB. */
- struct occurrence *children = nullptr;
-
- /* Pointer to the next "struct occurrence"s in the list of blocks
- sharing a common dominator. */
- struct occurrence *next = nullptr;
-
- /* The number of divisions that are in BB before compute_merit. The
- number of divisions that are in BB or post-dominate it after
- compute_merit. */
- int num_divisions = 0;
-
- /* True if the basic block has a division, false if it is a common
- dominator for basic blocks that do. If it is false and trapping
- math is active, BB is not a candidate for inserting a reciprocal. */
- bool bb_has_division = false;
-
- /* Construct a struct occurrence for basic block BB, and whose
- children list is headed by CHILDREN. */
- occurrence (basic_block bb, struct occurrence *children)
- : bb (bb), children (children)
- {
- bb->aux = this;
- }
-
- /* Destroy a struct occurrence and remove it from its basic block. */
- ~occurrence ()
- {
- bb->aux = nullptr;
- }
-
- /* Allocate memory for a struct occurrence from OCC_POOL. */
- static void* operator new (size_t);
-
- /* Return memory for a struct occurrence to OCC_POOL. */
- static void operator delete (void*, size_t);
-};
-
-static struct
-{
- /* Number of 1.0/X ops inserted. */
- int rdivs_inserted;
-
- /* Number of 1.0/FUNC ops inserted. */
- int rfuncs_inserted;
-} reciprocal_stats;
-
-static struct
-{
- /* Number of cexpi calls inserted. */
- int inserted;
-
- /* Number of conversions removed. */
- int conv_removed;
-
-} sincos_stats;
-
-static struct
-{
- /* Number of widening multiplication ops inserted. */
- int widen_mults_inserted;
-
- /* Number of integer multiply-and-accumulate ops inserted. */
- int maccs_inserted;
-
- /* Number of fp fused multiply-add ops inserted. */
- int fmas_inserted;
-
- /* Number of divmod calls inserted. */
- int divmod_calls_inserted;
-
- /* Number of highpart multiplication ops inserted. */
- int highpart_mults_inserted;
-} widen_mul_stats;
-
-/* The instance of "struct occurrence" representing the highest
- interesting block in the dominator tree. */
-static struct occurrence *occ_head;
-
-/* Allocation pool for getting instances of "struct occurrence". */
-static object_allocator<occurrence> *occ_pool;
-
-void* occurrence::operator new (size_t n)
-{
- gcc_assert (n == sizeof(occurrence));
- return occ_pool->allocate_raw ();
-}
-
-void occurrence::operator delete (void *occ, size_t n)
-{
- gcc_assert (n == sizeof(occurrence));
- occ_pool->remove_raw (occ);
-}
-
-/* Insert NEW_OCC into our subset of the dominator tree. P_HEAD points to a
- list of "struct occurrence"s, one per basic block, having IDOM as
- their common dominator.
-
- We try to insert NEW_OCC as deep as possible in the tree, and we also
- insert any other block that is a common dominator for BB and one
- block already in the tree. */
-
-static void
-insert_bb (struct occurrence *new_occ, basic_block idom,
- struct occurrence **p_head)
-{
- struct occurrence *occ, **p_occ;
-
- for (p_occ = p_head; (occ = *p_occ) != NULL; )
- {
- basic_block bb = new_occ->bb, occ_bb = occ->bb;
- basic_block dom = nearest_common_dominator (CDI_DOMINATORS, occ_bb, bb);
- if (dom == bb)
- {
- /* BB dominates OCC_BB. OCC becomes NEW_OCC's child: remove OCC
- from its list. */
- *p_occ = occ->next;
- occ->next = new_occ->children;
- new_occ->children = occ;
-
- /* Try the next block (it may as well be dominated by BB). */
- }
-
- else if (dom == occ_bb)
- {
- /* OCC_BB dominates BB. Tail recurse to look deeper. */
- insert_bb (new_occ, dom, &occ->children);
- return;
- }
-
- else if (dom != idom)
- {
- gcc_assert (!dom->aux);
-
- /* There is a dominator between IDOM and BB, add it and make
- two children out of NEW_OCC and OCC. First, remove OCC from
- its list. */
- *p_occ = occ->next;
- new_occ->next = occ;
- occ->next = NULL;
-
- /* None of the previous blocks has DOM as a dominator: if we tail
- recursed, we would reexamine them uselessly. Just switch BB with
- DOM, and go on looking for blocks dominated by DOM. */
- new_occ = new occurrence (dom, new_occ);
- }
-
- else
- {
- /* Nothing special, go on with the next element. */
- p_occ = &occ->next;
- }
- }
-
- /* No place was found as a child of IDOM. Make BB a sibling of IDOM. */
- new_occ->next = *p_head;
- *p_head = new_occ;
-}
-
-/* Register that we found a division in BB.
- IMPORTANCE is a measure of how much weighting to give
- that division. Use IMPORTANCE = 2 to register a single
- division. If the division is going to be found multiple
- times use 1 (as it is with squares). */
-
-static inline void
-register_division_in (basic_block bb, int importance)
-{
- struct occurrence *occ;
-
- occ = (struct occurrence *) bb->aux;
- if (!occ)
- {
- occ = new occurrence (bb, NULL);
- insert_bb (occ, ENTRY_BLOCK_PTR_FOR_FN (cfun), &occ_head);
- }
-
- occ->bb_has_division = true;
- occ->num_divisions += importance;
-}
-
-
-/* Compute the number of divisions that postdominate each block in OCC and
- its children. */
-
-static void
-compute_merit (struct occurrence *occ)
-{
- struct occurrence *occ_child;
- basic_block dom = occ->bb;
-
- for (occ_child = occ->children; occ_child; occ_child = occ_child->next)
- {
- basic_block bb;
- if (occ_child->children)
- compute_merit (occ_child);
-
- if (flag_exceptions)
- bb = single_noncomplex_succ (dom);
- else
- bb = dom;
-
- if (dominated_by_p (CDI_POST_DOMINATORS, bb, occ_child->bb))
- occ->num_divisions += occ_child->num_divisions;
- }
-}
-
-
-/* Return whether USE_STMT is a floating-point division by DEF. */
-static inline bool
-is_division_by (gimple *use_stmt, tree def)
-{
- return is_gimple_assign (use_stmt)
- && gimple_assign_rhs_code (use_stmt) == RDIV_EXPR
- && gimple_assign_rhs2 (use_stmt) == def
- /* Do not recognize x / x as valid division, as we are getting
- confused later by replacing all immediate uses x in such
- a stmt. */
- && gimple_assign_rhs1 (use_stmt) != def
- && !stmt_can_throw_internal (cfun, use_stmt);
-}
-
-/* Return TRUE if USE_STMT is a multiplication of DEF by A. */
-static inline bool
-is_mult_by (gimple *use_stmt, tree def, tree a)
-{
- if (gimple_code (use_stmt) == GIMPLE_ASSIGN
- && gimple_assign_rhs_code (use_stmt) == MULT_EXPR)
- {
- tree op0 = gimple_assign_rhs1 (use_stmt);
- tree op1 = gimple_assign_rhs2 (use_stmt);
-
- return (op0 == def && op1 == a)
- || (op0 == a && op1 == def);
- }
- return 0;
-}
-
-/* Return whether USE_STMT is DEF * DEF. */
-static inline bool
-is_square_of (gimple *use_stmt, tree def)
-{
- return is_mult_by (use_stmt, def, def);
-}
-
-/* Return whether USE_STMT is a floating-point division by
- DEF * DEF. */
-static inline bool
-is_division_by_square (gimple *use_stmt, tree def)
-{
- if (gimple_code (use_stmt) == GIMPLE_ASSIGN
- && gimple_assign_rhs_code (use_stmt) == RDIV_EXPR
- && gimple_assign_rhs1 (use_stmt) != gimple_assign_rhs2 (use_stmt)
- && !stmt_can_throw_internal (cfun, use_stmt))
- {
- tree denominator = gimple_assign_rhs2 (use_stmt);
- if (TREE_CODE (denominator) == SSA_NAME)
- return is_square_of (SSA_NAME_DEF_STMT (denominator), def);
- }
- return 0;
-}
-
-/* Walk the subset of the dominator tree rooted at OCC, setting the
- RECIP_DEF field to a definition of 1.0 / DEF that can be used in
- the given basic block. The field may be left NULL, of course,
- if it is not possible or profitable to do the optimization.
-
- DEF_BSI is an iterator pointing at the statement defining DEF.
- If RECIP_DEF is set, a dominator already has a computation that can
- be used.
-
- If should_insert_square_recip is set, then this also inserts
- the square of the reciprocal immediately after the definition
- of the reciprocal. */
-
-static void
-insert_reciprocals (gimple_stmt_iterator *def_gsi, struct occurrence *occ,
- tree def, tree recip_def, tree square_recip_def,
- int should_insert_square_recip, int threshold)
-{
- tree type;
- gassign *new_stmt, *new_square_stmt;
- gimple_stmt_iterator gsi;
- struct occurrence *occ_child;
-
- if (!recip_def
- && (occ->bb_has_division || !flag_trapping_math)
- /* Divide by two as all divisions are counted twice in
- the costing loop. */
- && occ->num_divisions / 2 >= threshold)
- {
- /* Make a variable with the replacement and substitute it. */
- type = TREE_TYPE (def);
- recip_def = create_tmp_reg (type, "reciptmp");
- new_stmt = gimple_build_assign (recip_def, RDIV_EXPR,
- build_one_cst (type), def);
-
- if (should_insert_square_recip)
- {
- square_recip_def = create_tmp_reg (type, "powmult_reciptmp");
- new_square_stmt = gimple_build_assign (square_recip_def, MULT_EXPR,
- recip_def, recip_def);
- }
-
- if (occ->bb_has_division)
- {
- /* Case 1: insert before an existing division. */
- gsi = gsi_after_labels (occ->bb);
- while (!gsi_end_p (gsi)
- && (!is_division_by (gsi_stmt (gsi), def))
- && (!is_division_by_square (gsi_stmt (gsi), def)))
- gsi_next (&gsi);
-
- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
- if (should_insert_square_recip)
- gsi_insert_before (&gsi, new_square_stmt, GSI_SAME_STMT);
- }
- else if (def_gsi && occ->bb == gsi_bb (*def_gsi))
- {
- /* Case 2: insert right after the definition. Note that this will
- never happen if the definition statement can throw, because in
- that case the sole successor of the statement's basic block will
- dominate all the uses as well. */
- gsi_insert_after (def_gsi, new_stmt, GSI_NEW_STMT);
- if (should_insert_square_recip)
- gsi_insert_after (def_gsi, new_square_stmt, GSI_NEW_STMT);
- }
- else
- {
- /* Case 3: insert in a basic block not containing defs/uses. */
- gsi = gsi_after_labels (occ->bb);
- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
- if (should_insert_square_recip)
- gsi_insert_before (&gsi, new_square_stmt, GSI_SAME_STMT);
- }
-
- reciprocal_stats.rdivs_inserted++;
-
- occ->recip_def_stmt = new_stmt;
- }
-
- occ->recip_def = recip_def;
- occ->square_recip_def = square_recip_def;
- for (occ_child = occ->children; occ_child; occ_child = occ_child->next)
- insert_reciprocals (def_gsi, occ_child, def, recip_def,
- square_recip_def, should_insert_square_recip,
- threshold);
-}
-
-/* Replace occurrences of expr / (x * x) with expr * ((1 / x) * (1 / x)).
- Take as argument the use for (x * x). */
-static inline void
-replace_reciprocal_squares (use_operand_p use_p)
-{
- gimple *use_stmt = USE_STMT (use_p);
- basic_block bb = gimple_bb (use_stmt);
- struct occurrence *occ = (struct occurrence *) bb->aux;
-
- if (optimize_bb_for_speed_p (bb) && occ->square_recip_def
- && occ->recip_def)
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- gimple_assign_set_rhs_code (use_stmt, MULT_EXPR);
- gimple_assign_set_rhs2 (use_stmt, occ->square_recip_def);
- SET_USE (use_p, occ->square_recip_def);
- fold_stmt_inplace (&gsi);
- update_stmt (use_stmt);
- }
-}
-
-
-/* Replace the division at USE_P with a multiplication by the reciprocal, if
- possible. */
-
-static inline void
-replace_reciprocal (use_operand_p use_p)
-{
- gimple *use_stmt = USE_STMT (use_p);
- basic_block bb = gimple_bb (use_stmt);
- struct occurrence *occ = (struct occurrence *) bb->aux;
-
- if (optimize_bb_for_speed_p (bb)
- && occ->recip_def && use_stmt != occ->recip_def_stmt)
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- gimple_assign_set_rhs_code (use_stmt, MULT_EXPR);
- SET_USE (use_p, occ->recip_def);
- fold_stmt_inplace (&gsi);
- update_stmt (use_stmt);
- }
-}
-
-
-/* Free OCC and return one more "struct occurrence" to be freed. */
-
-static struct occurrence *
-free_bb (struct occurrence *occ)
-{
- struct occurrence *child, *next;
-
- /* First get the two pointers hanging off OCC. */
- next = occ->next;
- child = occ->children;
- delete occ;
-
- /* Now ensure that we don't recurse unless it is necessary. */
- if (!child)
- return next;
- else
- {
- while (next)
- next = free_bb (next);
-
- return child;
- }
-}
-
-/* Transform sequences like
- t = sqrt (a)
- x = 1.0 / t;
- r1 = x * x;
- r2 = a * x;
- into:
- t = sqrt (a)
- r1 = 1.0 / a;
- r2 = t;
- x = r1 * r2;
- depending on the uses of x, r1, r2. This removes one multiplication and
- allows the sqrt and division operations to execute in parallel.
- DEF_GSI is the gsi of the initial division by sqrt that defines
- DEF (x in the example above). */
-
-static void
-optimize_recip_sqrt (gimple_stmt_iterator *def_gsi, tree def)
-{
- gimple *use_stmt;
- imm_use_iterator use_iter;
- gimple *stmt = gsi_stmt (*def_gsi);
- tree x = def;
- tree orig_sqrt_ssa_name = gimple_assign_rhs2 (stmt);
- tree div_rhs1 = gimple_assign_rhs1 (stmt);
-
- if (TREE_CODE (orig_sqrt_ssa_name) != SSA_NAME
- || TREE_CODE (div_rhs1) != REAL_CST
- || !real_equal (&TREE_REAL_CST (div_rhs1), &dconst1))
- return;
-
- gcall *sqrt_stmt
- = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (orig_sqrt_ssa_name));
-
- if (!sqrt_stmt || !gimple_call_lhs (sqrt_stmt))
- return;
-
- switch (gimple_call_combined_fn (sqrt_stmt))
- {
- CASE_CFN_SQRT:
- CASE_CFN_SQRT_FN:
- break;
-
- default:
- return;
- }
- tree a = gimple_call_arg (sqrt_stmt, 0);
-
- /* We have 'a' and 'x'. Now analyze the uses of 'x'. */
-
- /* Statements that use x in x * x. */
- auto_vec<gimple *> sqr_stmts;
- /* Statements that use x in a * x. */
- auto_vec<gimple *> mult_stmts;
- bool has_other_use = false;
- bool mult_on_main_path = false;
-
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, x)
- {
- if (is_gimple_debug (use_stmt))
- continue;
- if (is_square_of (use_stmt, x))
- {
- sqr_stmts.safe_push (use_stmt);
- if (gimple_bb (use_stmt) == gimple_bb (stmt))
- mult_on_main_path = true;
- }
- else if (is_mult_by (use_stmt, x, a))
- {
- mult_stmts.safe_push (use_stmt);
- if (gimple_bb (use_stmt) == gimple_bb (stmt))
- mult_on_main_path = true;
- }
- else
- has_other_use = true;
- }
-
- /* In the x * x and a * x cases we just rewire stmt operands or
- remove multiplications. In the has_other_use case we introduce
- a multiplication so make sure we don't introduce a multiplication
- on a path where there was none. */
- if (has_other_use && !mult_on_main_path)
- return;
-
- if (sqr_stmts.is_empty () && mult_stmts.is_empty ())
- return;
-
- /* If x = 1.0 / sqrt (a) has uses other than those optimized here we want
- to be able to compose it from the sqr and mult cases. */
- if (has_other_use && (sqr_stmts.is_empty () || mult_stmts.is_empty ()))
- return;
-
- if (dump_file)
- {
- fprintf (dump_file, "Optimizing reciprocal sqrt multiplications of\n");
- print_gimple_stmt (dump_file, sqrt_stmt, 0, TDF_NONE);
- print_gimple_stmt (dump_file, stmt, 0, TDF_NONE);
- fprintf (dump_file, "\n");
- }
-
- bool delete_div = !has_other_use;
- tree sqr_ssa_name = NULL_TREE;
- if (!sqr_stmts.is_empty ())
- {
- /* r1 = x * x. Transform the original
- x = 1.0 / t
- into
- tmp1 = 1.0 / a
- r1 = tmp1. */
-
- sqr_ssa_name
- = make_temp_ssa_name (TREE_TYPE (a), NULL, "recip_sqrt_sqr");
-
- if (dump_file)
- {
- fprintf (dump_file, "Replacing original division\n");
- print_gimple_stmt (dump_file, stmt, 0, TDF_NONE);
- fprintf (dump_file, "with new division\n");
- }
- stmt
- = gimple_build_assign (sqr_ssa_name, gimple_assign_rhs_code (stmt),
- gimple_assign_rhs1 (stmt), a);
- gsi_insert_before (def_gsi, stmt, GSI_SAME_STMT);
- gsi_remove (def_gsi, true);
- *def_gsi = gsi_for_stmt (stmt);
- fold_stmt_inplace (def_gsi);
- update_stmt (stmt);
-
- if (dump_file)
- print_gimple_stmt (dump_file, stmt, 0, TDF_NONE);
-
- delete_div = false;
- gimple *sqr_stmt;
- unsigned int i;
- FOR_EACH_VEC_ELT (sqr_stmts, i, sqr_stmt)
- {
- gimple_stmt_iterator gsi2 = gsi_for_stmt (sqr_stmt);
- gimple_assign_set_rhs_from_tree (&gsi2, sqr_ssa_name);
- update_stmt (sqr_stmt);
- }
- }
- if (!mult_stmts.is_empty ())
- {
- /* r2 = a * x. Transform this into:
- r2 = t (The original sqrt (a)). */
- unsigned int i;
- gimple *mult_stmt = NULL;
- FOR_EACH_VEC_ELT (mult_stmts, i, mult_stmt)
- {
- gimple_stmt_iterator gsi2 = gsi_for_stmt (mult_stmt);
-
- if (dump_file)
- {
- fprintf (dump_file, "Replacing squaring multiplication\n");
- print_gimple_stmt (dump_file, mult_stmt, 0, TDF_NONE);
- fprintf (dump_file, "with assignment\n");
- }
- gimple_assign_set_rhs_from_tree (&gsi2, orig_sqrt_ssa_name);
- fold_stmt_inplace (&gsi2);
- update_stmt (mult_stmt);
- if (dump_file)
- print_gimple_stmt (dump_file, mult_stmt, 0, TDF_NONE);
- }
- }
-
- if (has_other_use)
- {
- /* Using the two temporaries tmp1, tmp2 from above
- the original x is now:
- x = tmp1 * tmp2. */
- gcc_assert (orig_sqrt_ssa_name);
- gcc_assert (sqr_ssa_name);
-
- gimple *new_stmt
- = gimple_build_assign (x, MULT_EXPR,
- orig_sqrt_ssa_name, sqr_ssa_name);
- gsi_insert_after (def_gsi, new_stmt, GSI_NEW_STMT);
- update_stmt (stmt);
- }
- else if (delete_div)
- {
- /* Remove the original division. */
- gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
- gsi_remove (&gsi2, true);
- release_defs (stmt);
- }
- else
- release_ssa_name (x);
-}
-
-/* Look for floating-point divisions among DEF's uses, and try to
- replace them by multiplications with the reciprocal. Add
- as many statements computing the reciprocal as needed.
-
- DEF must be a GIMPLE register of a floating-point type. */
-
-static void
-execute_cse_reciprocals_1 (gimple_stmt_iterator *def_gsi, tree def)
-{
- use_operand_p use_p, square_use_p;
- imm_use_iterator use_iter, square_use_iter;
- tree square_def;
- struct occurrence *occ;
- int count = 0;
- int threshold;
- int square_recip_count = 0;
- int sqrt_recip_count = 0;
-
- gcc_assert (FLOAT_TYPE_P (TREE_TYPE (def)) && TREE_CODE (def) == SSA_NAME);
- threshold = targetm.min_divisions_for_recip_mul (TYPE_MODE (TREE_TYPE (def)));
-
- /* If DEF is a square (x * x), count the number of divisions by x.
- If there are more divisions by x than by (DEF * DEF), prefer to optimize
- the reciprocal of x instead of DEF. This improves cases like:
- def = x * x
- t0 = a / def
- t1 = b / def
- t2 = c / x
- Reciprocal optimization of x results in 1 division rather than 2 or 3. */
- gimple *def_stmt = SSA_NAME_DEF_STMT (def);
-
- if (is_gimple_assign (def_stmt)
- && gimple_assign_rhs_code (def_stmt) == MULT_EXPR
- && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
- && gimple_assign_rhs1 (def_stmt) == gimple_assign_rhs2 (def_stmt))
- {
- tree op0 = gimple_assign_rhs1 (def_stmt);
-
- FOR_EACH_IMM_USE_FAST (use_p, use_iter, op0)
- {
- gimple *use_stmt = USE_STMT (use_p);
- if (is_division_by (use_stmt, op0))
- sqrt_recip_count++;
- }
- }
-
- FOR_EACH_IMM_USE_FAST (use_p, use_iter, def)
- {
- gimple *use_stmt = USE_STMT (use_p);
- if (is_division_by (use_stmt, def))
- {
- register_division_in (gimple_bb (use_stmt), 2);
- count++;
- }
-
- if (is_square_of (use_stmt, def))
- {
- square_def = gimple_assign_lhs (use_stmt);
- FOR_EACH_IMM_USE_FAST (square_use_p, square_use_iter, square_def)
- {
- gimple *square_use_stmt = USE_STMT (square_use_p);
- if (is_division_by (square_use_stmt, square_def))
- {
- /* This is executed twice for each division by a square. */
- register_division_in (gimple_bb (square_use_stmt), 1);
- square_recip_count++;
- }
- }
- }
- }
-
- /* Square reciprocals were counted twice above. */
- square_recip_count /= 2;
-
- /* If it is more profitable to optimize 1 / x, don't optimize 1 / (x * x). */
- if (sqrt_recip_count > square_recip_count)
- goto out;
-
- /* Do the expensive part only if we can hope to optimize something. */
- if (count + square_recip_count >= threshold && count >= 1)
- {
- gimple *use_stmt;
- for (occ = occ_head; occ; occ = occ->next)
- {
- compute_merit (occ);
- insert_reciprocals (def_gsi, occ, def, NULL, NULL,
- square_recip_count, threshold);
- }
-
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, def)
- {
- if (is_division_by (use_stmt, def))
- {
- FOR_EACH_IMM_USE_ON_STMT (use_p, use_iter)
- replace_reciprocal (use_p);
- }
- else if (square_recip_count > 0 && is_square_of (use_stmt, def))
- {
- FOR_EACH_IMM_USE_ON_STMT (use_p, use_iter)
- {
- /* Find all uses of the square that are divisions and
- * replace them by multiplications with the inverse. */
- imm_use_iterator square_iterator;
- gimple *powmult_use_stmt = USE_STMT (use_p);
- tree powmult_def_name = gimple_assign_lhs (powmult_use_stmt);
-
- FOR_EACH_IMM_USE_STMT (powmult_use_stmt,
- square_iterator, powmult_def_name)
- FOR_EACH_IMM_USE_ON_STMT (square_use_p, square_iterator)
- {
- gimple *powmult_use_stmt = USE_STMT (square_use_p);
- if (is_division_by (powmult_use_stmt, powmult_def_name))
- replace_reciprocal_squares (square_use_p);
- }
- }
- }
- }
- }
-
-out:
- for (occ = occ_head; occ; )
- occ = free_bb (occ);
-
- occ_head = NULL;
-}
-
-/* Return an internal function that implements the reciprocal of CALL,
- or IFN_LAST if there is no such function that the target supports. */
-
-internal_fn
-internal_fn_reciprocal (gcall *call)
-{
- internal_fn ifn;
-
- switch (gimple_call_combined_fn (call))
- {
- CASE_CFN_SQRT:
- CASE_CFN_SQRT_FN:
- ifn = IFN_RSQRT;
- break;
-
- default:
- return IFN_LAST;
- }
-
- tree_pair types = direct_internal_fn_types (ifn, call);
- if (!direct_internal_fn_supported_p (ifn, types, OPTIMIZE_FOR_SPEED))
- return IFN_LAST;
-
- return ifn;
-}
-
-/* Go through all the floating-point SSA_NAMEs, and call
- execute_cse_reciprocals_1 on each of them. */
-namespace {
-
-const pass_data pass_data_cse_reciprocals =
-{
- GIMPLE_PASS, /* type */
- "recip", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_RECIP, /* tv_id */
- PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
-};
-
-class pass_cse_reciprocals : public gimple_opt_pass
-{
-public:
- pass_cse_reciprocals (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_cse_reciprocals, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *) { return optimize && flag_reciprocal_math; }
- virtual unsigned int execute (function *);
-
-}; // class pass_cse_reciprocals
-
-unsigned int
-pass_cse_reciprocals::execute (function *fun)
-{
- basic_block bb;
- tree arg;
-
- occ_pool = new object_allocator<occurrence> ("dominators for recip");
-
- memset (&reciprocal_stats, 0, sizeof (reciprocal_stats));
- calculate_dominance_info (CDI_DOMINATORS);
- calculate_dominance_info (CDI_POST_DOMINATORS);
-
- if (flag_checking)
- FOR_EACH_BB_FN (bb, fun)
- gcc_assert (!bb->aux);
-
- for (arg = DECL_ARGUMENTS (fun->decl); arg; arg = DECL_CHAIN (arg))
- if (FLOAT_TYPE_P (TREE_TYPE (arg))
- && is_gimple_reg (arg))
- {
- tree name = ssa_default_def (fun, arg);
- if (name)
- execute_cse_reciprocals_1 (NULL, name);
- }
-
- FOR_EACH_BB_FN (bb, fun)
- {
- tree def;
-
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- def = PHI_RESULT (phi);
- if (! virtual_operand_p (def)
- && FLOAT_TYPE_P (TREE_TYPE (def)))
- execute_cse_reciprocals_1 (NULL, def);
- }
-
- for (gimple_stmt_iterator gsi = gsi_after_labels (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
-
- if (gimple_has_lhs (stmt)
- && (def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF)) != NULL
- && FLOAT_TYPE_P (TREE_TYPE (def))
- && TREE_CODE (def) == SSA_NAME)
- {
- execute_cse_reciprocals_1 (&gsi, def);
- stmt = gsi_stmt (gsi);
- if (flag_unsafe_math_optimizations
- && is_gimple_assign (stmt)
- && gimple_assign_lhs (stmt) == def
- && !stmt_can_throw_internal (cfun, stmt)
- && gimple_assign_rhs_code (stmt) == RDIV_EXPR)
- optimize_recip_sqrt (&gsi, def);
- }
- }
-
- if (optimize_bb_for_size_p (bb))
- continue;
-
- /* Scan for a/func(b) and convert it to reciprocal a*rfunc(b). */
- for (gimple_stmt_iterator gsi = gsi_after_labels (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
-
- if (is_gimple_assign (stmt)
- && gimple_assign_rhs_code (stmt) == RDIV_EXPR)
- {
- tree arg1 = gimple_assign_rhs2 (stmt);
- gimple *stmt1;
-
- if (TREE_CODE (arg1) != SSA_NAME)
- continue;
-
- stmt1 = SSA_NAME_DEF_STMT (arg1);
-
- if (is_gimple_call (stmt1)
- && gimple_call_lhs (stmt1))
- {
- bool fail;
- imm_use_iterator ui;
- use_operand_p use_p;
- tree fndecl = NULL_TREE;
-
- gcall *call = as_a <gcall *> (stmt1);
- internal_fn ifn = internal_fn_reciprocal (call);
- if (ifn == IFN_LAST)
- {
- fndecl = gimple_call_fndecl (call);
- if (!fndecl
- || !fndecl_built_in_p (fndecl, BUILT_IN_MD))
- continue;
- fndecl = targetm.builtin_reciprocal (fndecl);
- if (!fndecl)
- continue;
- }
-
- /* Check that all uses of the SSA name are divisions,
- otherwise replacing the defining statement will do
- the wrong thing. */
- fail = false;
- FOR_EACH_IMM_USE_FAST (use_p, ui, arg1)
- {
- gimple *stmt2 = USE_STMT (use_p);
- if (is_gimple_debug (stmt2))
- continue;
- if (!is_gimple_assign (stmt2)
- || gimple_assign_rhs_code (stmt2) != RDIV_EXPR
- || gimple_assign_rhs1 (stmt2) == arg1
- || gimple_assign_rhs2 (stmt2) != arg1)
- {
- fail = true;
- break;
- }
- }
- if (fail)
- continue;
-
- gimple_replace_ssa_lhs (call, arg1);
- if (gimple_call_internal_p (call) != (ifn != IFN_LAST))
- {
- auto_vec<tree, 4> args;
- for (unsigned int i = 0;
- i < gimple_call_num_args (call); i++)
- args.safe_push (gimple_call_arg (call, i));
- gcall *stmt2;
- if (ifn == IFN_LAST)
- stmt2 = gimple_build_call_vec (fndecl, args);
- else
- stmt2 = gimple_build_call_internal_vec (ifn, args);
- gimple_call_set_lhs (stmt2, arg1);
- gimple_move_vops (stmt2, call);
- gimple_call_set_nothrow (stmt2,
- gimple_call_nothrow_p (call));
- gimple_stmt_iterator gsi2 = gsi_for_stmt (call);
- gsi_replace (&gsi2, stmt2, true);
- }
- else
- {
- if (ifn == IFN_LAST)
- gimple_call_set_fndecl (call, fndecl);
- else
- gimple_call_set_internal_fn (call, ifn);
- update_stmt (call);
- }
- reciprocal_stats.rfuncs_inserted++;
-
- FOR_EACH_IMM_USE_STMT (stmt, ui, arg1)
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
- gimple_assign_set_rhs_code (stmt, MULT_EXPR);
- fold_stmt_inplace (&gsi);
- update_stmt (stmt);
- }
- }
- }
- }
- }
-
- statistics_counter_event (fun, "reciprocal divs inserted",
- reciprocal_stats.rdivs_inserted);
- statistics_counter_event (fun, "reciprocal functions inserted",
- reciprocal_stats.rfuncs_inserted);
-
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- delete occ_pool;
- return 0;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_cse_reciprocals (gcc::context *ctxt)
-{
- return new pass_cse_reciprocals (ctxt);
-}
-
-/* If NAME is the result of a type conversion, look for other
- equivalent dominating or dominated conversions, and replace all
- uses with the earliest dominating name, removing the redundant
- conversions. Return the prevailing name. */
-
-static tree
-execute_cse_conv_1 (tree name)
-{
- if (SSA_NAME_IS_DEFAULT_DEF (name)
- || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
- return name;
-
- gimple *def_stmt = SSA_NAME_DEF_STMT (name);
-
- if (!gimple_assign_cast_p (def_stmt))
- return name;
-
- tree src = gimple_assign_rhs1 (def_stmt);
-
- if (TREE_CODE (src) != SSA_NAME)
- return name;
-
- imm_use_iterator use_iter;
- gimple *use_stmt;
-
- /* Find the earliest dominating def. */
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, src)
- {
- if (use_stmt == def_stmt
- || !gimple_assign_cast_p (use_stmt))
- continue;
-
- tree lhs = gimple_assign_lhs (use_stmt);
-
- if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
- || (gimple_assign_rhs1 (use_stmt)
- != gimple_assign_rhs1 (def_stmt))
- || !types_compatible_p (TREE_TYPE (name), TREE_TYPE (lhs)))
- continue;
-
- bool use_dominates;
- if (gimple_bb (def_stmt) == gimple_bb (use_stmt))
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- while (!gsi_end_p (gsi) && gsi_stmt (gsi) != def_stmt)
- gsi_next (&gsi);
- use_dominates = !gsi_end_p (gsi);
- }
- else if (dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt),
- gimple_bb (def_stmt)))
- use_dominates = false;
- else if (dominated_by_p (CDI_DOMINATORS, gimple_bb (def_stmt),
- gimple_bb (use_stmt)))
- use_dominates = true;
- else
- continue;
-
- if (use_dominates)
- {
- std::swap (name, lhs);
- std::swap (def_stmt, use_stmt);
- }
- }
-
- /* Now go through all uses of SRC again, replacing the equivalent
- dominated conversions. We may replace defs that were not
- dominated by the then-prevailing defs when we first visited
- them. */
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, src)
- {
- if (use_stmt == def_stmt
- || !gimple_assign_cast_p (use_stmt))
- continue;
-
- tree lhs = gimple_assign_lhs (use_stmt);
-
- if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
- || (gimple_assign_rhs1 (use_stmt)
- != gimple_assign_rhs1 (def_stmt))
- || !types_compatible_p (TREE_TYPE (name), TREE_TYPE (lhs)))
- continue;
-
- if (gimple_bb (def_stmt) == gimple_bb (use_stmt)
- || dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt),
- gimple_bb (def_stmt)))
- {
- sincos_stats.conv_removed++;
-
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- replace_uses_by (lhs, name);
- gsi_remove (&gsi, true);
- }
- }
-
- return name;
-}
-
-/* Records an occurrence at statement USE_STMT in the vector of trees
- STMTS if it is dominated by *TOP_BB or dominates it or this basic block
- is not yet initialized. Returns true if the occurrence was pushed on
- the vector. Adjusts *TOP_BB to be the basic block dominating all
- statements in the vector. */
-
-static bool
-maybe_record_sincos (vec<gimple *> *stmts,
- basic_block *top_bb, gimple *use_stmt)
-{
- basic_block use_bb = gimple_bb (use_stmt);
- if (*top_bb
- && (*top_bb == use_bb
- || dominated_by_p (CDI_DOMINATORS, use_bb, *top_bb)))
- stmts->safe_push (use_stmt);
- else if (!*top_bb
- || dominated_by_p (CDI_DOMINATORS, *top_bb, use_bb))
- {
- stmts->safe_push (use_stmt);
- *top_bb = use_bb;
- }
- else
- return false;
-
- return true;
-}
-
-/* Look for sin, cos and cexpi calls with the same argument NAME and
- create a single call to cexpi CSEing the result in this case.
- We first walk over all immediate uses of the argument collecting
- statements that we can CSE in a vector and in a second pass replace
- the statement rhs with a REALPART or IMAGPART expression on the
- result of the cexpi call we insert before the use statement that
- dominates all other candidates. */
-
-static bool
-execute_cse_sincos_1 (tree name)
-{
- gimple_stmt_iterator gsi;
- imm_use_iterator use_iter;
- tree fndecl, res, type = NULL_TREE;
- gimple *def_stmt, *use_stmt, *stmt;
- int seen_cos = 0, seen_sin = 0, seen_cexpi = 0;
- auto_vec<gimple *> stmts;
- basic_block top_bb = NULL;
- int i;
- bool cfg_changed = false;
-
- name = execute_cse_conv_1 (name);
-
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, name)
- {
- if (gimple_code (use_stmt) != GIMPLE_CALL
- || !gimple_call_lhs (use_stmt))
- continue;
-
- switch (gimple_call_combined_fn (use_stmt))
- {
- CASE_CFN_COS:
- seen_cos |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
- break;
-
- CASE_CFN_SIN:
- seen_sin |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
- break;
-
- CASE_CFN_CEXPI:
- seen_cexpi |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
- break;
-
- default:;
- continue;
- }
-
- tree t = mathfn_built_in_type (gimple_call_combined_fn (use_stmt));
- if (!type)
- {
- type = t;
- t = TREE_TYPE (name);
- }
- /* This checks that NAME has the right type in the first round,
- and, in subsequent rounds, that the built_in type is the same
- type, or a compatible type. */
- if (type != t && !types_compatible_p (type, t))
- return false;
- }
- if (seen_cos + seen_sin + seen_cexpi <= 1)
- return false;
-
- /* Simply insert cexpi at the beginning of top_bb but not earlier than
- the name def statement. */
- fndecl = mathfn_built_in (type, BUILT_IN_CEXPI);
- if (!fndecl)
- return false;
- stmt = gimple_build_call (fndecl, 1, name);
- res = make_temp_ssa_name (TREE_TYPE (TREE_TYPE (fndecl)), stmt, "sincostmp");
- gimple_call_set_lhs (stmt, res);
-
- def_stmt = SSA_NAME_DEF_STMT (name);
- if (!SSA_NAME_IS_DEFAULT_DEF (name)
- && gimple_code (def_stmt) != GIMPLE_PHI
- && gimple_bb (def_stmt) == top_bb)
- {
- gsi = gsi_for_stmt (def_stmt);
- gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
- }
- else
- {
- gsi = gsi_after_labels (top_bb);
- gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
- }
- sincos_stats.inserted++;
-
- /* And adjust the recorded old call sites. */
- for (i = 0; stmts.iterate (i, &use_stmt); ++i)
- {
- tree rhs = NULL;
-
- switch (gimple_call_combined_fn (use_stmt))
- {
- CASE_CFN_COS:
- rhs = fold_build1 (REALPART_EXPR, type, res);
- break;
-
- CASE_CFN_SIN:
- rhs = fold_build1 (IMAGPART_EXPR, type, res);
- break;
-
- CASE_CFN_CEXPI:
- rhs = res;
- break;
-
- default:;
- gcc_unreachable ();
- }
-
- /* Replace call with a copy. */
- stmt = gimple_build_assign (gimple_call_lhs (use_stmt), rhs);
-
- gsi = gsi_for_stmt (use_stmt);
- gsi_replace (&gsi, stmt, true);
- if (gimple_purge_dead_eh_edges (gimple_bb (stmt)))
- cfg_changed = true;
- }
-
- return cfg_changed;
-}
-
-/* To evaluate powi(x,n), the floating point value x raised to the
- constant integer exponent n, we use a hybrid algorithm that
- combines the "window method" with look-up tables. For an
- introduction to exponentiation algorithms and "addition chains",
- see section 4.6.3, "Evaluation of Powers" of Donald E. Knuth,
- "Seminumerical Algorithms", Vol. 2, "The Art of Computer Programming",
- 3rd Edition, 1998, and Daniel M. Gordon, "A Survey of Fast Exponentiation
- Methods", Journal of Algorithms, Vol. 27, pp. 129-146, 1998. */
-
-/* Provide a default value for POWI_MAX_MULTS, the maximum number of
- multiplications to inline before calling the system library's pow
- function. powi(x,n) requires at worst 2*bits(n)-2 multiplications,
- so this default never requires calling pow, powf or powl. */
-
-#ifndef POWI_MAX_MULTS
-#define POWI_MAX_MULTS (2*HOST_BITS_PER_WIDE_INT-2)
-#endif
-
-/* The size of the "optimal power tree" lookup table. All
- exponents less than this value are simply looked up in the
- powi_table below. This threshold is also used to size the
- cache of pseudo registers that hold intermediate results. */
-#define POWI_TABLE_SIZE 256
-
-/* The size, in bits of the window, used in the "window method"
- exponentiation algorithm. This is equivalent to a radix of
- (1<<POWI_WINDOW_SIZE) in the corresponding "m-ary method". */
-#define POWI_WINDOW_SIZE 3
-
-/* The following table is an efficient representation of an
- "optimal power tree". For each value, i, the corresponding
- value, j, in the table states than an optimal evaluation
- sequence for calculating pow(x,i) can be found by evaluating
- pow(x,j)*pow(x,i-j). An optimal power tree for the first
- 100 integers is given in Knuth's "Seminumerical algorithms". */
-
-static const unsigned char powi_table[POWI_TABLE_SIZE] =
- {
- 0, 1, 1, 2, 2, 3, 3, 4, /* 0 - 7 */
- 4, 6, 5, 6, 6, 10, 7, 9, /* 8 - 15 */
- 8, 16, 9, 16, 10, 12, 11, 13, /* 16 - 23 */
- 12, 17, 13, 18, 14, 24, 15, 26, /* 24 - 31 */
- 16, 17, 17, 19, 18, 33, 19, 26, /* 32 - 39 */
- 20, 25, 21, 40, 22, 27, 23, 44, /* 40 - 47 */
- 24, 32, 25, 34, 26, 29, 27, 44, /* 48 - 55 */
- 28, 31, 29, 34, 30, 60, 31, 36, /* 56 - 63 */
- 32, 64, 33, 34, 34, 46, 35, 37, /* 64 - 71 */
- 36, 65, 37, 50, 38, 48, 39, 69, /* 72 - 79 */
- 40, 49, 41, 43, 42, 51, 43, 58, /* 80 - 87 */
- 44, 64, 45, 47, 46, 59, 47, 76, /* 88 - 95 */
- 48, 65, 49, 66, 50, 67, 51, 66, /* 96 - 103 */
- 52, 70, 53, 74, 54, 104, 55, 74, /* 104 - 111 */
- 56, 64, 57, 69, 58, 78, 59, 68, /* 112 - 119 */
- 60, 61, 61, 80, 62, 75, 63, 68, /* 120 - 127 */
- 64, 65, 65, 128, 66, 129, 67, 90, /* 128 - 135 */
- 68, 73, 69, 131, 70, 94, 71, 88, /* 136 - 143 */
- 72, 128, 73, 98, 74, 132, 75, 121, /* 144 - 151 */
- 76, 102, 77, 124, 78, 132, 79, 106, /* 152 - 159 */
- 80, 97, 81, 160, 82, 99, 83, 134, /* 160 - 167 */
- 84, 86, 85, 95, 86, 160, 87, 100, /* 168 - 175 */
- 88, 113, 89, 98, 90, 107, 91, 122, /* 176 - 183 */
- 92, 111, 93, 102, 94, 126, 95, 150, /* 184 - 191 */
- 96, 128, 97, 130, 98, 133, 99, 195, /* 192 - 199 */
- 100, 128, 101, 123, 102, 164, 103, 138, /* 200 - 207 */
- 104, 145, 105, 146, 106, 109, 107, 149, /* 208 - 215 */
- 108, 200, 109, 146, 110, 170, 111, 157, /* 216 - 223 */
- 112, 128, 113, 130, 114, 182, 115, 132, /* 224 - 231 */
- 116, 200, 117, 132, 118, 158, 119, 206, /* 232 - 239 */
- 120, 240, 121, 162, 122, 147, 123, 152, /* 240 - 247 */
- 124, 166, 125, 214, 126, 138, 127, 153, /* 248 - 255 */
- };
-
-
-/* Return the number of multiplications required to calculate
- powi(x,n) where n is less than POWI_TABLE_SIZE. This is a
- subroutine of powi_cost. CACHE is an array indicating
- which exponents have already been calculated. */
-
-static int
-powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
-{
- /* If we've already calculated this exponent, then this evaluation
- doesn't require any additional multiplications. */
- if (cache[n])
- return 0;
-
- cache[n] = true;
- return powi_lookup_cost (n - powi_table[n], cache)
- + powi_lookup_cost (powi_table[n], cache) + 1;
-}
-
-/* Return the number of multiplications required to calculate
- powi(x,n) for an arbitrary x, given the exponent N. This
- function needs to be kept in sync with powi_as_mults below. */
-
-static int
-powi_cost (HOST_WIDE_INT n)
-{
- bool cache[POWI_TABLE_SIZE];
- unsigned HOST_WIDE_INT digit;
- unsigned HOST_WIDE_INT val;
- int result;
-
- if (n == 0)
- return 0;
-
- /* Ignore the reciprocal when calculating the cost. */
- val = (n < 0) ? -n : n;
-
- /* Initialize the exponent cache. */
- memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
- cache[1] = true;
-
- result = 0;
-
- while (val >= POWI_TABLE_SIZE)
- {
- if (val & 1)
- {
- digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
- result += powi_lookup_cost (digit, cache)
- + POWI_WINDOW_SIZE + 1;
- val >>= POWI_WINDOW_SIZE;
- }
- else
- {
- val >>= 1;
- result++;
- }
- }
-
- return result + powi_lookup_cost (val, cache);
-}
-
-/* Recursive subroutine of powi_as_mults. This function takes the
- array, CACHE, of already calculated exponents and an exponent N and
- returns a tree that corresponds to CACHE[1]**N, with type TYPE. */
-
-static tree
-powi_as_mults_1 (gimple_stmt_iterator *gsi, location_t loc, tree type,
- HOST_WIDE_INT n, tree *cache)
-{
- tree op0, op1, ssa_target;
- unsigned HOST_WIDE_INT digit;
- gassign *mult_stmt;
-
- if (n < POWI_TABLE_SIZE && cache[n])
- return cache[n];
-
- ssa_target = make_temp_ssa_name (type, NULL, "powmult");
-
- if (n < POWI_TABLE_SIZE)
- {
- cache[n] = ssa_target;
- op0 = powi_as_mults_1 (gsi, loc, type, n - powi_table[n], cache);
- op1 = powi_as_mults_1 (gsi, loc, type, powi_table[n], cache);
- }
- else if (n & 1)
- {
- digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
- op0 = powi_as_mults_1 (gsi, loc, type, n - digit, cache);
- op1 = powi_as_mults_1 (gsi, loc, type, digit, cache);
- }
- else
- {
- op0 = powi_as_mults_1 (gsi, loc, type, n >> 1, cache);
- op1 = op0;
- }
-
- mult_stmt = gimple_build_assign (ssa_target, MULT_EXPR, op0, op1);
- gimple_set_location (mult_stmt, loc);
- gsi_insert_before (gsi, mult_stmt, GSI_SAME_STMT);
-
- return ssa_target;
-}
-
-/* Convert ARG0**N to a tree of multiplications of ARG0 with itself.
- This function needs to be kept in sync with powi_cost above. */
-
-tree
-powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
- tree arg0, HOST_WIDE_INT n)
-{
- tree cache[POWI_TABLE_SIZE], result, type = TREE_TYPE (arg0);
- gassign *div_stmt;
- tree target;
-
- if (n == 0)
- return build_one_cst (type);
-
- memset (cache, 0, sizeof (cache));
- cache[1] = arg0;
-
- result = powi_as_mults_1 (gsi, loc, type, (n < 0) ? -n : n, cache);
- if (n >= 0)
- return result;
-
- /* If the original exponent was negative, reciprocate the result. */
- target = make_temp_ssa_name (type, NULL, "powmult");
- div_stmt = gimple_build_assign (target, RDIV_EXPR,
- build_real (type, dconst1), result);
- gimple_set_location (div_stmt, loc);
- gsi_insert_before (gsi, div_stmt, GSI_SAME_STMT);
-
- return target;
-}
-
-/* ARG0 and N are the two arguments to a powi builtin in GSI with
- location info LOC. If the arguments are appropriate, create an
- equivalent sequence of statements prior to GSI using an optimal
- number of multiplications, and return an expession holding the
- result. */
-
-static tree
-gimple_expand_builtin_powi (gimple_stmt_iterator *gsi, location_t loc,
- tree arg0, HOST_WIDE_INT n)
-{
- /* Avoid largest negative number. */
- if (n != -n
- && ((n >= -1 && n <= 2)
- || (optimize_function_for_speed_p (cfun)
- && powi_cost (n) <= POWI_MAX_MULTS)))
- return powi_as_mults (gsi, loc, arg0, n);
-
- return NULL_TREE;
-}
-
-/* Build a gimple call statement that calls FN with argument ARG.
- Set the lhs of the call statement to a fresh SSA name. Insert the
- statement prior to GSI's current position, and return the fresh
- SSA name. */
-
-static tree
-build_and_insert_call (gimple_stmt_iterator *gsi, location_t loc,
- tree fn, tree arg)
-{
- gcall *call_stmt;
- tree ssa_target;
-
- call_stmt = gimple_build_call (fn, 1, arg);
- ssa_target = make_temp_ssa_name (TREE_TYPE (arg), NULL, "powroot");
- gimple_set_lhs (call_stmt, ssa_target);
- gimple_set_location (call_stmt, loc);
- gsi_insert_before (gsi, call_stmt, GSI_SAME_STMT);
-
- return ssa_target;
-}
-
-/* Build a gimple binary operation with the given CODE and arguments
- ARG0, ARG1, assigning the result to a new SSA name for variable
- TARGET. Insert the statement prior to GSI's current position, and
- return the fresh SSA name.*/
-
-static tree
-build_and_insert_binop (gimple_stmt_iterator *gsi, location_t loc,
- const char *name, enum tree_code code,
- tree arg0, tree arg1)
-{
- tree result = make_temp_ssa_name (TREE_TYPE (arg0), NULL, name);
- gassign *stmt = gimple_build_assign (result, code, arg0, arg1);
- gimple_set_location (stmt, loc);
- gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
- return result;
-}
-
-/* Build a gimple reference operation with the given CODE and argument
- ARG, assigning the result to a new SSA name of TYPE with NAME.
- Insert the statement prior to GSI's current position, and return
- the fresh SSA name. */
-
-static inline tree
-build_and_insert_ref (gimple_stmt_iterator *gsi, location_t loc, tree type,
- const char *name, enum tree_code code, tree arg0)
-{
- tree result = make_temp_ssa_name (type, NULL, name);
- gimple *stmt = gimple_build_assign (result, build1 (code, type, arg0));
- gimple_set_location (stmt, loc);
- gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
- return result;
-}
-
-/* Build a gimple assignment to cast VAL to TYPE. Insert the statement
- prior to GSI's current position, and return the fresh SSA name. */
-
-static tree
-build_and_insert_cast (gimple_stmt_iterator *gsi, location_t loc,
- tree type, tree val)
-{
- tree result = make_ssa_name (type);
- gassign *stmt = gimple_build_assign (result, NOP_EXPR, val);
- gimple_set_location (stmt, loc);
- gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
- return result;
-}
-
-struct pow_synth_sqrt_info
-{
- bool *factors;
- unsigned int deepest;
- unsigned int num_mults;
-};
-
-/* Return true iff the real value C can be represented as a
- sum of powers of 0.5 up to N. That is:
- C == SUM<i from 1..N> (a[i]*(0.5**i)) where a[i] is either 0 or 1.
- Record in INFO the various parameters of the synthesis algorithm such
- as the factors a[i], the maximum 0.5 power and the number of
- multiplications that will be required. */
-
-bool
-representable_as_half_series_p (REAL_VALUE_TYPE c, unsigned n,
- struct pow_synth_sqrt_info *info)
-{
- REAL_VALUE_TYPE factor = dconsthalf;
- REAL_VALUE_TYPE remainder = c;
-
- info->deepest = 0;
- info->num_mults = 0;
- memset (info->factors, 0, n * sizeof (bool));
-
- for (unsigned i = 0; i < n; i++)
- {
- REAL_VALUE_TYPE res;
-
- /* If something inexact happened bail out now. */
- if (real_arithmetic (&res, MINUS_EXPR, &remainder, &factor))
- return false;
-
- /* We have hit zero. The number is representable as a sum
- of powers of 0.5. */
- if (real_equal (&res, &dconst0))
- {
- info->factors[i] = true;
- info->deepest = i + 1;
- return true;
- }
- else if (!REAL_VALUE_NEGATIVE (res))
- {
- remainder = res;
- info->factors[i] = true;
- info->num_mults++;
- }
- else
- info->factors[i] = false;
-
- real_arithmetic (&factor, MULT_EXPR, &factor, &dconsthalf);
- }
- return false;
-}
-
-/* Return the tree corresponding to FN being applied
- to ARG N times at GSI and LOC.
- Look up previous results from CACHE if need be.
- cache[0] should contain just plain ARG i.e. FN applied to ARG 0 times. */
-
-static tree
-get_fn_chain (tree arg, unsigned int n, gimple_stmt_iterator *gsi,
- tree fn, location_t loc, tree *cache)
-{
- tree res = cache[n];
- if (!res)
- {
- tree prev = get_fn_chain (arg, n - 1, gsi, fn, loc, cache);
- res = build_and_insert_call (gsi, loc, fn, prev);
- cache[n] = res;
- }
-
- return res;
-}
-
-/* Print to STREAM the repeated application of function FNAME to ARG
- N times. So, for FNAME = "foo", ARG = "x", N = 2 it would print:
- "foo (foo (x))". */
-
-static void
-print_nested_fn (FILE* stream, const char *fname, const char* arg,
- unsigned int n)
-{
- if (n == 0)
- fprintf (stream, "%s", arg);
- else
- {
- fprintf (stream, "%s (", fname);
- print_nested_fn (stream, fname, arg, n - 1);
- fprintf (stream, ")");
- }
-}
-
-/* Print to STREAM the fractional sequence of sqrt chains
- applied to ARG, described by INFO. Used for the dump file. */
-
-static void
-dump_fractional_sqrt_sequence (FILE *stream, const char *arg,
- struct pow_synth_sqrt_info *info)
-{
- for (unsigned int i = 0; i < info->deepest; i++)
- {
- bool is_set = info->factors[i];
- if (is_set)
- {
- print_nested_fn (stream, "sqrt", arg, i + 1);
- if (i != info->deepest - 1)
- fprintf (stream, " * ");
- }
- }
-}
-
-/* Print to STREAM a representation of raising ARG to an integer
- power N. Used for the dump file. */
-
-static void
-dump_integer_part (FILE *stream, const char* arg, HOST_WIDE_INT n)
-{
- if (n > 1)
- fprintf (stream, "powi (%s, " HOST_WIDE_INT_PRINT_DEC ")", arg, n);
- else if (n == 1)
- fprintf (stream, "%s", arg);
-}
-
-/* Attempt to synthesize a POW[F] (ARG0, ARG1) call using chains of
- square roots. Place at GSI and LOC. Limit the maximum depth
- of the sqrt chains to MAX_DEPTH. Return the tree holding the
- result of the expanded sequence or NULL_TREE if the expansion failed.
-
- This routine assumes that ARG1 is a real number with a fractional part
- (the integer exponent case will have been handled earlier in
- gimple_expand_builtin_pow).
-
- For ARG1 > 0.0:
- * For ARG1 composed of a whole part WHOLE_PART and a fractional part
- FRAC_PART i.e. WHOLE_PART == floor (ARG1) and
- FRAC_PART == ARG1 - WHOLE_PART:
- Produce POWI (ARG0, WHOLE_PART) * POW (ARG0, FRAC_PART) where
- POW (ARG0, FRAC_PART) is expanded as a product of square root chains
- if it can be expressed as such, that is if FRAC_PART satisfies:
- FRAC_PART == <SUM from i = 1 until MAX_DEPTH> (a[i] * (0.5**i))
- where integer a[i] is either 0 or 1.
-
- Example:
- POW (x, 3.625) == POWI (x, 3) * POW (x, 0.625)
- --> POWI (x, 3) * SQRT (x) * SQRT (SQRT (SQRT (x)))
-
- For ARG1 < 0.0 there are two approaches:
- * (A) Expand to 1.0 / POW (ARG0, -ARG1) where POW (ARG0, -ARG1)
- is calculated as above.
-
- Example:
- POW (x, -5.625) == 1.0 / POW (x, 5.625)
- --> 1.0 / (POWI (x, 5) * SQRT (x) * SQRT (SQRT (SQRT (x))))
-
- * (B) : WHOLE_PART := - ceil (abs (ARG1))
- FRAC_PART := ARG1 - WHOLE_PART
- and expand to POW (x, FRAC_PART) / POWI (x, WHOLE_PART).
- Example:
- POW (x, -5.875) == POW (x, 0.125) / POWI (X, 6)
- --> SQRT (SQRT (SQRT (x))) / (POWI (x, 6))
-
- For ARG1 < 0.0 we choose between (A) and (B) depending on
- how many multiplications we'd have to do.
- So, for the example in (B): POW (x, -5.875), if we were to
- follow algorithm (A) we would produce:
- 1.0 / POWI (X, 5) * SQRT (X) * SQRT (SQRT (X)) * SQRT (SQRT (SQRT (X)))
- which contains more multiplications than approach (B).
-
- Hopefully, this approach will eliminate potentially expensive POW library
- calls when unsafe floating point math is enabled and allow the compiler to
- further optimise the multiplies, square roots and divides produced by this
- function. */
-
-static tree
-expand_pow_as_sqrts (gimple_stmt_iterator *gsi, location_t loc,
- tree arg0, tree arg1, HOST_WIDE_INT max_depth)
-{
- tree type = TREE_TYPE (arg0);
- machine_mode mode = TYPE_MODE (type);
- tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
- bool one_over = true;
-
- if (!sqrtfn)
- return NULL_TREE;
-
- if (TREE_CODE (arg1) != REAL_CST)
- return NULL_TREE;
-
- REAL_VALUE_TYPE exp_init = TREE_REAL_CST (arg1);
-
- gcc_assert (max_depth > 0);
- tree *cache = XALLOCAVEC (tree, max_depth + 1);
-
- struct pow_synth_sqrt_info synth_info;
- synth_info.factors = XALLOCAVEC (bool, max_depth + 1);
- synth_info.deepest = 0;
- synth_info.num_mults = 0;
-
- bool neg_exp = REAL_VALUE_NEGATIVE (exp_init);
- REAL_VALUE_TYPE exp = real_value_abs (&exp_init);
-
- /* The whole and fractional parts of exp. */
- REAL_VALUE_TYPE whole_part;
- REAL_VALUE_TYPE frac_part;
-
- real_floor (&whole_part, mode, &exp);
- real_arithmetic (&frac_part, MINUS_EXPR, &exp, &whole_part);
-
-
- REAL_VALUE_TYPE ceil_whole = dconst0;
- REAL_VALUE_TYPE ceil_fract = dconst0;
-
- if (neg_exp)
- {
- real_ceil (&ceil_whole, mode, &exp);
- real_arithmetic (&ceil_fract, MINUS_EXPR, &ceil_whole, &exp);
- }
-
- if (!representable_as_half_series_p (frac_part, max_depth, &synth_info))
- return NULL_TREE;
-
- /* Check whether it's more profitable to not use 1.0 / ... */
- if (neg_exp)
- {
- struct pow_synth_sqrt_info alt_synth_info;
- alt_synth_info.factors = XALLOCAVEC (bool, max_depth + 1);
- alt_synth_info.deepest = 0;
- alt_synth_info.num_mults = 0;
-
- if (representable_as_half_series_p (ceil_fract, max_depth,
- &alt_synth_info)
- && alt_synth_info.deepest <= synth_info.deepest
- && alt_synth_info.num_mults < synth_info.num_mults)
- {
- whole_part = ceil_whole;
- frac_part = ceil_fract;
- synth_info.deepest = alt_synth_info.deepest;
- synth_info.num_mults = alt_synth_info.num_mults;
- memcpy (synth_info.factors, alt_synth_info.factors,
- (max_depth + 1) * sizeof (bool));
- one_over = false;
- }
- }
-
- HOST_WIDE_INT n = real_to_integer (&whole_part);
- REAL_VALUE_TYPE cint;
- real_from_integer (&cint, VOIDmode, n, SIGNED);
-
- if (!real_identical (&whole_part, &cint))
- return NULL_TREE;
-
- if (powi_cost (n) + synth_info.num_mults > POWI_MAX_MULTS)
- return NULL_TREE;
-
- memset (cache, 0, (max_depth + 1) * sizeof (tree));
-
- tree integer_res = n == 0 ? build_real (type, dconst1) : arg0;
-
- /* Calculate the integer part of the exponent. */
- if (n > 1)
- {
- integer_res = gimple_expand_builtin_powi (gsi, loc, arg0, n);
- if (!integer_res)
- return NULL_TREE;
- }
-
- if (dump_file)
- {
- char string[64];
-
- real_to_decimal (string, &exp_init, sizeof (string), 0, 1);
- fprintf (dump_file, "synthesizing pow (x, %s) as:\n", string);
-
- if (neg_exp)
- {
- if (one_over)
- {
- fprintf (dump_file, "1.0 / (");
- dump_integer_part (dump_file, "x", n);
- if (n > 0)
- fprintf (dump_file, " * ");
- dump_fractional_sqrt_sequence (dump_file, "x", &synth_info);
- fprintf (dump_file, ")");
- }
- else
- {
- dump_fractional_sqrt_sequence (dump_file, "x", &synth_info);
- fprintf (dump_file, " / (");
- dump_integer_part (dump_file, "x", n);
- fprintf (dump_file, ")");
- }
- }
- else
- {
- dump_fractional_sqrt_sequence (dump_file, "x", &synth_info);
- if (n > 0)
- fprintf (dump_file, " * ");
- dump_integer_part (dump_file, "x", n);
- }
-
- fprintf (dump_file, "\ndeepest sqrt chain: %d\n", synth_info.deepest);
- }
-
-
- tree fract_res = NULL_TREE;
- cache[0] = arg0;
-
- /* Calculate the fractional part of the exponent. */
- for (unsigned i = 0; i < synth_info.deepest; i++)
- {
- if (synth_info.factors[i])
- {
- tree sqrt_chain = get_fn_chain (arg0, i + 1, gsi, sqrtfn, loc, cache);
-
- if (!fract_res)
- fract_res = sqrt_chain;
-
- else
- fract_res = build_and_insert_binop (gsi, loc, "powroot", MULT_EXPR,
- fract_res, sqrt_chain);
- }
- }
-
- tree res = NULL_TREE;
-
- if (neg_exp)
- {
- if (one_over)
- {
- if (n > 0)
- res = build_and_insert_binop (gsi, loc, "powroot", MULT_EXPR,
- fract_res, integer_res);
- else
- res = fract_res;
-
- res = build_and_insert_binop (gsi, loc, "powrootrecip", RDIV_EXPR,
- build_real (type, dconst1), res);
- }
- else
- {
- res = build_and_insert_binop (gsi, loc, "powroot", RDIV_EXPR,
- fract_res, integer_res);
- }
- }
- else
- res = build_and_insert_binop (gsi, loc, "powroot", MULT_EXPR,
- fract_res, integer_res);
- return res;
-}
-
-/* ARG0 and ARG1 are the two arguments to a pow builtin call in GSI
- with location info LOC. If possible, create an equivalent and
- less expensive sequence of statements prior to GSI, and return an
- expession holding the result. */
-
-static tree
-gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
- tree arg0, tree arg1)
-{
- REAL_VALUE_TYPE c, cint, dconst1_3, dconst1_4, dconst1_6;
- REAL_VALUE_TYPE c2, dconst3;
- HOST_WIDE_INT n;
- tree type, sqrtfn, cbrtfn, sqrt_arg0, result, cbrt_x, powi_cbrt_x;
- machine_mode mode;
- bool speed_p = optimize_bb_for_speed_p (gsi_bb (*gsi));
- bool hw_sqrt_exists, c_is_int, c2_is_int;
-
- dconst1_4 = dconst1;
- SET_REAL_EXP (&dconst1_4, REAL_EXP (&dconst1_4) - 2);
-
- /* If the exponent isn't a constant, there's nothing of interest
- to be done. */
- if (TREE_CODE (arg1) != REAL_CST)
- return NULL_TREE;
-
- /* Don't perform the operation if flag_signaling_nans is on
- and the operand is a signaling NaN. */
- if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))
- && ((TREE_CODE (arg0) == REAL_CST
- && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0)))
- || REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1))))
- return NULL_TREE;
-
- /* If the exponent is equivalent to an integer, expand to an optimal
- multiplication sequence when profitable. */
- c = TREE_REAL_CST (arg1);
- n = real_to_integer (&c);
- real_from_integer (&cint, VOIDmode, n, SIGNED);
- c_is_int = real_identical (&c, &cint);
-
- if (c_is_int
- && ((n >= -1 && n <= 2)
- || (flag_unsafe_math_optimizations
- && speed_p
- && powi_cost (n) <= POWI_MAX_MULTS)))
- return gimple_expand_builtin_powi (gsi, loc, arg0, n);
-
- /* Attempt various optimizations using sqrt and cbrt. */
- type = TREE_TYPE (arg0);
- mode = TYPE_MODE (type);
- sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
-
- /* Optimize pow(x,0.5) = sqrt(x). This replacement is always safe
- unless signed zeros must be maintained. pow(-0,0.5) = +0, while
- sqrt(-0) = -0. */
- if (sqrtfn
- && real_equal (&c, &dconsthalf)
- && !HONOR_SIGNED_ZEROS (mode))
- return build_and_insert_call (gsi, loc, sqrtfn, arg0);
-
- hw_sqrt_exists = optab_handler (sqrt_optab, mode) != CODE_FOR_nothing;
-
- /* Optimize pow(x,1./3.) = cbrt(x). This requires unsafe math
- optimizations since 1./3. is not exactly representable. If x
- is negative and finite, the correct value of pow(x,1./3.) is
- a NaN with the "invalid" exception raised, because the value
- of 1./3. actually has an even denominator. The correct value
- of cbrt(x) is a negative real value. */
- cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
- dconst1_3 = real_value_truncate (mode, dconst_third ());
-
- if (flag_unsafe_math_optimizations
- && cbrtfn
- && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
- && real_equal (&c, &dconst1_3))
- return build_and_insert_call (gsi, loc, cbrtfn, arg0);
-
- /* Optimize pow(x,1./6.) = cbrt(sqrt(x)). Don't do this optimization
- if we don't have a hardware sqrt insn. */
- dconst1_6 = dconst1_3;
- SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
-
- if (flag_unsafe_math_optimizations
- && sqrtfn
- && cbrtfn
- && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
- && speed_p
- && hw_sqrt_exists
- && real_equal (&c, &dconst1_6))
- {
- /* sqrt(x) */
- sqrt_arg0 = build_and_insert_call (gsi, loc, sqrtfn, arg0);
-
- /* cbrt(sqrt(x)) */
- return build_and_insert_call (gsi, loc, cbrtfn, sqrt_arg0);
- }
-
-
- /* Attempt to expand the POW as a product of square root chains.
- Expand the 0.25 case even when otpimising for size. */
- if (flag_unsafe_math_optimizations
- && sqrtfn
- && hw_sqrt_exists
- && (speed_p || real_equal (&c, &dconst1_4))
- && !HONOR_SIGNED_ZEROS (mode))
- {
- unsigned int max_depth = speed_p
- ? param_max_pow_sqrt_depth
- : 2;
-
- tree expand_with_sqrts
- = expand_pow_as_sqrts (gsi, loc, arg0, arg1, max_depth);
-
- if (expand_with_sqrts)
- return expand_with_sqrts;
- }
-
- real_arithmetic (&c2, MULT_EXPR, &c, &dconst2);
- n = real_to_integer (&c2);
- real_from_integer (&cint, VOIDmode, n, SIGNED);
- c2_is_int = real_identical (&c2, &cint);
-
- /* Optimize pow(x,c), where 3c = n for some nonzero integer n, into
-
- powi(x, n/3) * powi(cbrt(x), n%3), n > 0;
- 1.0 / (powi(x, abs(n)/3) * powi(cbrt(x), abs(n)%3)), n < 0.
-
- Do not calculate the first factor when n/3 = 0. As cbrt(x) is
- different from pow(x, 1./3.) due to rounding and behavior with
- negative x, we need to constrain this transformation to unsafe
- math and positive x or finite math. */
- real_from_integer (&dconst3, VOIDmode, 3, SIGNED);
- real_arithmetic (&c2, MULT_EXPR, &c, &dconst3);
- real_round (&c2, mode, &c2);
- n = real_to_integer (&c2);
- real_from_integer (&cint, VOIDmode, n, SIGNED);
- real_arithmetic (&c2, RDIV_EXPR, &cint, &dconst3);
- real_convert (&c2, mode, &c2);
-
- if (flag_unsafe_math_optimizations
- && cbrtfn
- && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
- && real_identical (&c2, &c)
- && !c2_is_int
- && optimize_function_for_speed_p (cfun)
- && powi_cost (n / 3) <= POWI_MAX_MULTS)
- {
- tree powi_x_ndiv3 = NULL_TREE;
-
- /* Attempt to fold powi(arg0, abs(n/3)) into multiplies. If not
- possible or profitable, give up. Skip the degenerate case when
- abs(n) < 3, where the result is always 1. */
- if (absu_hwi (n) >= 3)
- {
- powi_x_ndiv3 = gimple_expand_builtin_powi (gsi, loc, arg0,
- abs_hwi (n / 3));
- if (!powi_x_ndiv3)
- return NULL_TREE;
- }
-
- /* Calculate powi(cbrt(x), n%3). Don't use gimple_expand_builtin_powi
- as that creates an unnecessary variable. Instead, just produce
- either cbrt(x) or cbrt(x) * cbrt(x). */
- cbrt_x = build_and_insert_call (gsi, loc, cbrtfn, arg0);
-
- if (absu_hwi (n) % 3 == 1)
- powi_cbrt_x = cbrt_x;
- else
- powi_cbrt_x = build_and_insert_binop (gsi, loc, "powroot", MULT_EXPR,
- cbrt_x, cbrt_x);
-
- /* Multiply the two subexpressions, unless powi(x,abs(n)/3) = 1. */
- if (absu_hwi (n) < 3)
- result = powi_cbrt_x;
- else
- result = build_and_insert_binop (gsi, loc, "powroot", MULT_EXPR,
- powi_x_ndiv3, powi_cbrt_x);
-
- /* If n is negative, reciprocate the result. */
- if (n < 0)
- result = build_and_insert_binop (gsi, loc, "powroot", RDIV_EXPR,
- build_real (type, dconst1), result);
-
- return result;
- }
-
- /* No optimizations succeeded. */
- return NULL_TREE;
-}
-
-/* ARG is the argument to a cabs builtin call in GSI with location info
- LOC. Create a sequence of statements prior to GSI that calculates
- sqrt(R*R + I*I), where R and I are the real and imaginary components
- of ARG, respectively. Return an expression holding the result. */
-
-static tree
-gimple_expand_builtin_cabs (gimple_stmt_iterator *gsi, location_t loc, tree arg)
-{
- tree real_part, imag_part, addend1, addend2, sum, result;
- tree type = TREE_TYPE (TREE_TYPE (arg));
- tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
- machine_mode mode = TYPE_MODE (type);
-
- if (!flag_unsafe_math_optimizations
- || !optimize_bb_for_speed_p (gimple_bb (gsi_stmt (*gsi)))
- || !sqrtfn
- || optab_handler (sqrt_optab, mode) == CODE_FOR_nothing)
- return NULL_TREE;
-
- real_part = build_and_insert_ref (gsi, loc, type, "cabs",
- REALPART_EXPR, arg);
- addend1 = build_and_insert_binop (gsi, loc, "cabs", MULT_EXPR,
- real_part, real_part);
- imag_part = build_and_insert_ref (gsi, loc, type, "cabs",
- IMAGPART_EXPR, arg);
- addend2 = build_and_insert_binop (gsi, loc, "cabs", MULT_EXPR,
- imag_part, imag_part);
- sum = build_and_insert_binop (gsi, loc, "cabs", PLUS_EXPR, addend1, addend2);
- result = build_and_insert_call (gsi, loc, sqrtfn, sum);
-
- return result;
-}
-
-/* Go through all calls to sin, cos and cexpi and call execute_cse_sincos_1
- on the SSA_NAME argument of each of them. Also expand powi(x,n) into
- an optimal number of multiplies, when n is a constant. */
-
-namespace {
-
-const pass_data pass_data_cse_sincos =
-{
- GIMPLE_PASS, /* type */
- "sincos", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_SINCOS, /* tv_id */
- PROP_ssa, /* properties_required */
- PROP_gimple_opt_math, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
-};
-
-class pass_cse_sincos : public gimple_opt_pass
-{
-public:
- pass_cse_sincos (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_cse_sincos, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- /* We no longer require either sincos or cexp, since powi expansion
- piggybacks on this pass. */
- return optimize;
- }
-
- virtual unsigned int execute (function *);
-
-}; // class pass_cse_sincos
-
-unsigned int
-pass_cse_sincos::execute (function *fun)
-{
- basic_block bb;
- bool cfg_changed = false;
-
- calculate_dominance_info (CDI_DOMINATORS);
- memset (&sincos_stats, 0, sizeof (sincos_stats));
-
- FOR_EACH_BB_FN (bb, fun)
- {
- gimple_stmt_iterator gsi;
- bool cleanup_eh = false;
-
- for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
-
- /* Only the last stmt in a bb could throw, no need to call
- gimple_purge_dead_eh_edges if we change something in the middle
- of a basic block. */
- cleanup_eh = false;
-
- if (is_gimple_call (stmt)
- && gimple_call_lhs (stmt))
- {
- tree arg, arg0, arg1, result;
- HOST_WIDE_INT n;
- location_t loc;
-
- switch (gimple_call_combined_fn (stmt))
- {
- CASE_CFN_COS:
- CASE_CFN_SIN:
- CASE_CFN_CEXPI:
- arg = gimple_call_arg (stmt, 0);
- /* Make sure we have either sincos or cexp. */
- if (!targetm.libc_has_function (function_c99_math_complex,
- TREE_TYPE (arg))
- && !targetm.libc_has_function (function_sincos,
- TREE_TYPE (arg)))
- break;
-
- if (TREE_CODE (arg) == SSA_NAME)
- cfg_changed |= execute_cse_sincos_1 (arg);
- break;
-
- CASE_CFN_POW:
- arg0 = gimple_call_arg (stmt, 0);
- arg1 = gimple_call_arg (stmt, 1);
-
- loc = gimple_location (stmt);
- result = gimple_expand_builtin_pow (&gsi, loc, arg0, arg1);
-
- if (result)
- {
- tree lhs = gimple_get_lhs (stmt);
- gassign *new_stmt = gimple_build_assign (lhs, result);
- gimple_set_location (new_stmt, loc);
- unlink_stmt_vdef (stmt);
- gsi_replace (&gsi, new_stmt, true);
- cleanup_eh = true;
- if (gimple_vdef (stmt))
- release_ssa_name (gimple_vdef (stmt));
- }
- break;
-
- CASE_CFN_POWI:
- arg0 = gimple_call_arg (stmt, 0);
- arg1 = gimple_call_arg (stmt, 1);
- loc = gimple_location (stmt);
-
- if (real_minus_onep (arg0))
- {
- tree t0, t1, cond, one, minus_one;
- gassign *stmt;
-
- t0 = TREE_TYPE (arg0);
- t1 = TREE_TYPE (arg1);
- one = build_real (t0, dconst1);
- minus_one = build_real (t0, dconstm1);
-
- cond = make_temp_ssa_name (t1, NULL, "powi_cond");
- stmt = gimple_build_assign (cond, BIT_AND_EXPR,
- arg1, build_int_cst (t1, 1));
- gimple_set_location (stmt, loc);
- gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
-
- result = make_temp_ssa_name (t0, NULL, "powi");
- stmt = gimple_build_assign (result, COND_EXPR, cond,
- minus_one, one);
- gimple_set_location (stmt, loc);
- gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
- }
- else
- {
- if (!tree_fits_shwi_p (arg1))
- break;
-
- n = tree_to_shwi (arg1);
- result = gimple_expand_builtin_powi (&gsi, loc, arg0, n);
- }
-
- if (result)
- {
- tree lhs = gimple_get_lhs (stmt);
- gassign *new_stmt = gimple_build_assign (lhs, result);
- gimple_set_location (new_stmt, loc);
- unlink_stmt_vdef (stmt);
- gsi_replace (&gsi, new_stmt, true);
- cleanup_eh = true;
- if (gimple_vdef (stmt))
- release_ssa_name (gimple_vdef (stmt));
- }
- break;
-
- CASE_CFN_CABS:
- arg0 = gimple_call_arg (stmt, 0);
- loc = gimple_location (stmt);
- result = gimple_expand_builtin_cabs (&gsi, loc, arg0);
-
- if (result)
- {
- tree lhs = gimple_get_lhs (stmt);
- gassign *new_stmt = gimple_build_assign (lhs, result);
- gimple_set_location (new_stmt, loc);
- unlink_stmt_vdef (stmt);
- gsi_replace (&gsi, new_stmt, true);
- cleanup_eh = true;
- if (gimple_vdef (stmt))
- release_ssa_name (gimple_vdef (stmt));
- }
- break;
-
- default:;
- }
- }
- }
- if (cleanup_eh)
- cfg_changed |= gimple_purge_dead_eh_edges (bb);
- }
-
- statistics_counter_event (fun, "sincos statements inserted",
- sincos_stats.inserted);
- statistics_counter_event (fun, "conv statements removed",
- sincos_stats.conv_removed);
-
- return cfg_changed ? TODO_cleanup_cfg : 0;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_cse_sincos (gcc::context *ctxt)
-{
- return new pass_cse_sincos (ctxt);
-}
-
-/* Return true if stmt is a type conversion operation that can be stripped
- when used in a widening multiply operation. */
-static bool
-widening_mult_conversion_strippable_p (tree result_type, gimple *stmt)
-{
- enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-
- if (TREE_CODE (result_type) == INTEGER_TYPE)
- {
- tree op_type;
- tree inner_op_type;
-
- if (!CONVERT_EXPR_CODE_P (rhs_code))
- return false;
-
- op_type = TREE_TYPE (gimple_assign_lhs (stmt));
-
- /* If the type of OP has the same precision as the result, then
- we can strip this conversion. The multiply operation will be
- selected to create the correct extension as a by-product. */
- if (TYPE_PRECISION (result_type) == TYPE_PRECISION (op_type))
- return true;
-
- /* We can also strip a conversion if it preserves the signed-ness of
- the operation and doesn't narrow the range. */
- inner_op_type = TREE_TYPE (gimple_assign_rhs1 (stmt));
-
- /* If the inner-most type is unsigned, then we can strip any
- intermediate widening operation. If it's signed, then the
- intermediate widening operation must also be signed. */
- if ((TYPE_UNSIGNED (inner_op_type)
- || TYPE_UNSIGNED (op_type) == TYPE_UNSIGNED (inner_op_type))
- && TYPE_PRECISION (op_type) > TYPE_PRECISION (inner_op_type))
- return true;
-
- return false;
- }
-
- return rhs_code == FIXED_CONVERT_EXPR;
-}
-
-/* Return true if RHS is a suitable operand for a widening multiplication,
- assuming a target type of TYPE.
- There are two cases:
-
- - RHS makes some value at least twice as wide. Store that value
- in *NEW_RHS_OUT if so, and store its type in *TYPE_OUT.
-
- - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,
- but leave *TYPE_OUT untouched. */
-
-static bool
-is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out,
- tree *new_rhs_out)
-{
- gimple *stmt;
- tree type1, rhs1;
-
- if (TREE_CODE (rhs) == SSA_NAME)
- {
- stmt = SSA_NAME_DEF_STMT (rhs);
- if (is_gimple_assign (stmt))
- {
- if (! widening_mult_conversion_strippable_p (type, stmt))
- rhs1 = rhs;
- else
- {
- rhs1 = gimple_assign_rhs1 (stmt);
-
- if (TREE_CODE (rhs1) == INTEGER_CST)
- {
- *new_rhs_out = rhs1;
- *type_out = NULL;
- return true;
- }
- }
- }
- else
- rhs1 = rhs;
-
- type1 = TREE_TYPE (rhs1);
-
- if (TREE_CODE (type1) != TREE_CODE (type)
- || TYPE_PRECISION (type1) * 2 > TYPE_PRECISION (type))
- return false;
-
- *new_rhs_out = rhs1;
- *type_out = type1;
- return true;
- }
-
- if (TREE_CODE (rhs) == INTEGER_CST)
- {
- *new_rhs_out = rhs;
- *type_out = NULL;
- return true;
- }
-
- return false;
-}
-
-/* Return true if STMT performs a widening multiplication, assuming the
- output type is TYPE. If so, store the unwidened types of the operands
- in *TYPE1_OUT and *TYPE2_OUT respectively. Also fill *RHS1_OUT and
- *RHS2_OUT such that converting those operands to types *TYPE1_OUT
- and *TYPE2_OUT would give the operands of the multiplication. */
-
-static bool
-is_widening_mult_p (gimple *stmt,
- tree *type1_out, tree *rhs1_out,
- tree *type2_out, tree *rhs2_out)
-{
- tree type = TREE_TYPE (gimple_assign_lhs (stmt));
-
- if (TREE_CODE (type) == INTEGER_TYPE)
- {
- if (TYPE_OVERFLOW_TRAPS (type))
- return false;
- }
- else if (TREE_CODE (type) != FIXED_POINT_TYPE)
- return false;
-
- if (!is_widening_mult_rhs_p (type, gimple_assign_rhs1 (stmt), type1_out,
- rhs1_out))
- return false;
-
- if (!is_widening_mult_rhs_p (type, gimple_assign_rhs2 (stmt), type2_out,
- rhs2_out))
- return false;
-
- if (*type1_out == NULL)
- {
- if (*type2_out == NULL || !int_fits_type_p (*rhs1_out, *type2_out))
- return false;
- *type1_out = *type2_out;
- }
-
- if (*type2_out == NULL)
- {
- if (!int_fits_type_p (*rhs2_out, *type1_out))
- return false;
- *type2_out = *type1_out;
- }
-
- /* Ensure that the larger of the two operands comes first. */
- if (TYPE_PRECISION (*type1_out) < TYPE_PRECISION (*type2_out))
- {
- std::swap (*type1_out, *type2_out);
- std::swap (*rhs1_out, *rhs2_out);
- }
-
- return true;
-}
-
-/* Check to see if the CALL statement is an invocation of copysign
- with 1. being the first argument. */
-static bool
-is_copysign_call_with_1 (gimple *call)
-{
- gcall *c = dyn_cast <gcall *> (call);
- if (! c)
- return false;
-
- enum combined_fn code = gimple_call_combined_fn (c);
-
- if (code == CFN_LAST)
- return false;
-
- if (builtin_fn_p (code))
- {
- switch (as_builtin_fn (code))
- {
- CASE_FLT_FN (BUILT_IN_COPYSIGN):
- CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN):
- return real_onep (gimple_call_arg (c, 0));
- default:
- return false;
- }
- }
-
- if (internal_fn_p (code))
- {
- switch (as_internal_fn (code))
- {
- case IFN_COPYSIGN:
- return real_onep (gimple_call_arg (c, 0));
- default:
- return false;
- }
- }
-
- return false;
-}
-
-/* Try to expand the pattern x * copysign (1, y) into xorsign (x, y).
- This only happens when the xorsign optab is defined, if the
- pattern is not a xorsign pattern or if expansion fails FALSE is
- returned, otherwise TRUE is returned. */
-static bool
-convert_expand_mult_copysign (gimple *stmt, gimple_stmt_iterator *gsi)
-{
- tree treeop0, treeop1, lhs, type;
- location_t loc = gimple_location (stmt);
- lhs = gimple_assign_lhs (stmt);
- treeop0 = gimple_assign_rhs1 (stmt);
- treeop1 = gimple_assign_rhs2 (stmt);
- type = TREE_TYPE (lhs);
- machine_mode mode = TYPE_MODE (type);
-
- if (HONOR_SNANS (type))
- return false;
-
- if (TREE_CODE (treeop0) == SSA_NAME && TREE_CODE (treeop1) == SSA_NAME)
- {
- gimple *call0 = SSA_NAME_DEF_STMT (treeop0);
- if (!has_single_use (treeop0) || !is_copysign_call_with_1 (call0))
- {
- call0 = SSA_NAME_DEF_STMT (treeop1);
- if (!has_single_use (treeop1) || !is_copysign_call_with_1 (call0))
- return false;
-
- treeop1 = treeop0;
- }
- if (optab_handler (xorsign_optab, mode) == CODE_FOR_nothing)
- return false;
-
- gcall *c = as_a<gcall*> (call0);
- treeop0 = gimple_call_arg (c, 1);
-
- gcall *call_stmt
- = gimple_build_call_internal (IFN_XORSIGN, 2, treeop1, treeop0);
- gimple_set_lhs (call_stmt, lhs);
- gimple_set_location (call_stmt, loc);
- gsi_replace (gsi, call_stmt, true);
- return true;
- }
-
- return false;
-}
-
-/* Process a single gimple statement STMT, which has a MULT_EXPR as
- its rhs, and try to convert it into a WIDEN_MULT_EXPR. The return
- value is true iff we converted the statement. */
-
-static bool
-convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi)
-{
- tree lhs, rhs1, rhs2, type, type1, type2;
- enum insn_code handler;
- scalar_int_mode to_mode, from_mode, actual_mode;
- optab op;
- int actual_precision;
- location_t loc = gimple_location (stmt);
- bool from_unsigned1, from_unsigned2;
-
- lhs = gimple_assign_lhs (stmt);
- type = TREE_TYPE (lhs);
- if (TREE_CODE (type) != INTEGER_TYPE)
- return false;
-
- if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
- return false;
-
- to_mode = SCALAR_INT_TYPE_MODE (type);
- from_mode = SCALAR_INT_TYPE_MODE (type1);
- if (to_mode == from_mode)
- return false;
-
- from_unsigned1 = TYPE_UNSIGNED (type1);
- from_unsigned2 = TYPE_UNSIGNED (type2);
-
- if (from_unsigned1 && from_unsigned2)
- op = umul_widen_optab;
- else if (!from_unsigned1 && !from_unsigned2)
- op = smul_widen_optab;
- else
- op = usmul_widen_optab;
-
- handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
- &actual_mode);
-
- if (handler == CODE_FOR_nothing)
- {
- if (op != smul_widen_optab)
- {
- /* We can use a signed multiply with unsigned types as long as
- there is a wider mode to use, or it is the smaller of the two
- types that is unsigned. Note that type1 >= type2, always. */
- if ((TYPE_UNSIGNED (type1)
- && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
- || (TYPE_UNSIGNED (type2)
- && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
- {
- if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
- || GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
- return false;
- }
-
- op = smul_widen_optab;
- handler = find_widening_optab_handler_and_mode (op, to_mode,
- from_mode,
- &actual_mode);
-
- if (handler == CODE_FOR_nothing)
- return false;
-
- from_unsigned1 = from_unsigned2 = false;
- }
- else
- {
- /* Expand can synthesize smul_widen_optab if the target
- supports umul_widen_optab. */
- op = umul_widen_optab;
- handler = find_widening_optab_handler_and_mode (op, to_mode,
- from_mode,
- &actual_mode);
- if (handler == CODE_FOR_nothing)
- return false;
- }
- }
-
- /* Ensure that the inputs to the handler are in the correct precison
- for the opcode. This will be the full mode size. */
- actual_precision = GET_MODE_PRECISION (actual_mode);
- if (2 * actual_precision > TYPE_PRECISION (type))
- return false;
- if (actual_precision != TYPE_PRECISION (type1)
- || from_unsigned1 != TYPE_UNSIGNED (type1))
- rhs1 = build_and_insert_cast (gsi, loc,
- build_nonstandard_integer_type
- (actual_precision, from_unsigned1), rhs1);
- if (actual_precision != TYPE_PRECISION (type2)
- || from_unsigned2 != TYPE_UNSIGNED (type2))
- rhs2 = build_and_insert_cast (gsi, loc,
- build_nonstandard_integer_type
- (actual_precision, from_unsigned2), rhs2);
-
- /* Handle constants. */
- if (TREE_CODE (rhs1) == INTEGER_CST)
- rhs1 = fold_convert (type1, rhs1);
- if (TREE_CODE (rhs2) == INTEGER_CST)
- rhs2 = fold_convert (type2, rhs2);
-
- gimple_assign_set_rhs1 (stmt, rhs1);
- gimple_assign_set_rhs2 (stmt, rhs2);
- gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
- update_stmt (stmt);
- widen_mul_stats.widen_mults_inserted++;
- return true;
-}
-
-/* Process a single gimple statement STMT, which is found at the
- iterator GSI and has a either a PLUS_EXPR or a MINUS_EXPR as its
- rhs (given by CODE), and try to convert it into a
- WIDEN_MULT_PLUS_EXPR or a WIDEN_MULT_MINUS_EXPR. The return value
- is true iff we converted the statement. */
-
-static bool
-convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt,
- enum tree_code code)
-{
- gimple *rhs1_stmt = NULL, *rhs2_stmt = NULL;
- gimple *conv1_stmt = NULL, *conv2_stmt = NULL, *conv_stmt;
- tree type, type1, type2, optype;
- tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
- enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
- optab this_optab;
- enum tree_code wmult_code;
- enum insn_code handler;
- scalar_mode to_mode, from_mode, actual_mode;
- location_t loc = gimple_location (stmt);
- int actual_precision;
- bool from_unsigned1, from_unsigned2;
-
- lhs = gimple_assign_lhs (stmt);
- type = TREE_TYPE (lhs);
- if (TREE_CODE (type) != INTEGER_TYPE
- && TREE_CODE (type) != FIXED_POINT_TYPE)
- return false;
-
- if (code == MINUS_EXPR)
- wmult_code = WIDEN_MULT_MINUS_EXPR;
- else
- wmult_code = WIDEN_MULT_PLUS_EXPR;
-
- rhs1 = gimple_assign_rhs1 (stmt);
- rhs2 = gimple_assign_rhs2 (stmt);
-
- if (TREE_CODE (rhs1) == SSA_NAME)
- {
- rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
- if (is_gimple_assign (rhs1_stmt))
- rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
- }
-
- if (TREE_CODE (rhs2) == SSA_NAME)
- {
- rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
- if (is_gimple_assign (rhs2_stmt))
- rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
- }
-
- /* Allow for one conversion statement between the multiply
- and addition/subtraction statement. If there are more than
- one conversions then we assume they would invalidate this
- transformation. If that's not the case then they should have
- been folded before now. */
- if (CONVERT_EXPR_CODE_P (rhs1_code))
- {
- conv1_stmt = rhs1_stmt;
- rhs1 = gimple_assign_rhs1 (rhs1_stmt);
- if (TREE_CODE (rhs1) == SSA_NAME)
- {
- rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
- if (is_gimple_assign (rhs1_stmt))
- rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
- }
- else
- return false;
- }
- if (CONVERT_EXPR_CODE_P (rhs2_code))
- {
- conv2_stmt = rhs2_stmt;
- rhs2 = gimple_assign_rhs1 (rhs2_stmt);
- if (TREE_CODE (rhs2) == SSA_NAME)
- {
- rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
- if (is_gimple_assign (rhs2_stmt))
- rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
- }
- else
- return false;
- }
-
- /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
- is_widening_mult_p, but we still need the rhs returns.
-
- It might also appear that it would be sufficient to use the existing
- operands of the widening multiply, but that would limit the choice of
- multiply-and-accumulate instructions.
-
- If the widened-multiplication result has more than one uses, it is
- probably wiser not to do the conversion. Also restrict this operation
- to single basic block to avoid moving the multiply to a different block
- with a higher execution frequency. */
- if (code == PLUS_EXPR
- && (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
- {
- if (!has_single_use (rhs1)
- || gimple_bb (rhs1_stmt) != gimple_bb (stmt)
- || !is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
- &type2, &mult_rhs2))
- return false;
- add_rhs = rhs2;
- conv_stmt = conv1_stmt;
- }
- else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
- {
- if (!has_single_use (rhs2)
- || gimple_bb (rhs2_stmt) != gimple_bb (stmt)
- || !is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
- &type2, &mult_rhs2))
- return false;
- add_rhs = rhs1;
- conv_stmt = conv2_stmt;
- }
- else
- return false;
-
- to_mode = SCALAR_TYPE_MODE (type);
- from_mode = SCALAR_TYPE_MODE (type1);
- if (to_mode == from_mode)
- return false;
-
- from_unsigned1 = TYPE_UNSIGNED (type1);
- from_unsigned2 = TYPE_UNSIGNED (type2);
- optype = type1;
-
- /* There's no such thing as a mixed sign madd yet, so use a wider mode. */
- if (from_unsigned1 != from_unsigned2)
- {
- if (!INTEGRAL_TYPE_P (type))
- return false;
- /* We can use a signed multiply with unsigned types as long as
- there is a wider mode to use, or it is the smaller of the two
- types that is unsigned. Note that type1 >= type2, always. */
- if ((from_unsigned1
- && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
- || (from_unsigned2
- && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
- {
- if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
- || GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
- return false;
- }
-
- from_unsigned1 = from_unsigned2 = false;
- optype = build_nonstandard_integer_type (GET_MODE_PRECISION (from_mode),
- false);
- }
-
- /* If there was a conversion between the multiply and addition
- then we need to make sure it fits a multiply-and-accumulate.
- The should be a single mode change which does not change the
- value. */
- if (conv_stmt)
- {
- /* We use the original, unmodified data types for this. */
- tree from_type = TREE_TYPE (gimple_assign_rhs1 (conv_stmt));
- tree to_type = TREE_TYPE (gimple_assign_lhs (conv_stmt));
- int data_size = TYPE_PRECISION (type1) + TYPE_PRECISION (type2);
- bool is_unsigned = TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2);
-
- if (TYPE_PRECISION (from_type) > TYPE_PRECISION (to_type))
- {
- /* Conversion is a truncate. */
- if (TYPE_PRECISION (to_type) < data_size)
- return false;
- }
- else if (TYPE_PRECISION (from_type) < TYPE_PRECISION (to_type))
- {
- /* Conversion is an extend. Check it's the right sort. */
- if (TYPE_UNSIGNED (from_type) != is_unsigned
- && !(is_unsigned && TYPE_PRECISION (from_type) > data_size))
- return false;
- }
- /* else convert is a no-op for our purposes. */
- }
-
- /* Verify that the machine can perform a widening multiply
- accumulate in this mode/signedness combination, otherwise
- this transformation is likely to pessimize code. */
- this_optab = optab_for_tree_code (wmult_code, optype, optab_default);
- handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
- from_mode, &actual_mode);
-
- if (handler == CODE_FOR_nothing)
- return false;
-
- /* Ensure that the inputs to the handler are in the correct precison
- for the opcode. This will be the full mode size. */
- actual_precision = GET_MODE_PRECISION (actual_mode);
- if (actual_precision != TYPE_PRECISION (type1)
- || from_unsigned1 != TYPE_UNSIGNED (type1))
- mult_rhs1 = build_and_insert_cast (gsi, loc,
- build_nonstandard_integer_type
- (actual_precision, from_unsigned1),
- mult_rhs1);
- if (actual_precision != TYPE_PRECISION (type2)
- || from_unsigned2 != TYPE_UNSIGNED (type2))
- mult_rhs2 = build_and_insert_cast (gsi, loc,
- build_nonstandard_integer_type
- (actual_precision, from_unsigned2),
- mult_rhs2);
-
- if (!useless_type_conversion_p (type, TREE_TYPE (add_rhs)))
- add_rhs = build_and_insert_cast (gsi, loc, type, add_rhs);
-
- /* Handle constants. */
- if (TREE_CODE (mult_rhs1) == INTEGER_CST)
- mult_rhs1 = fold_convert (type1, mult_rhs1);
- if (TREE_CODE (mult_rhs2) == INTEGER_CST)
- mult_rhs2 = fold_convert (type2, mult_rhs2);
-
- gimple_assign_set_rhs_with_ops (gsi, wmult_code, mult_rhs1, mult_rhs2,
- add_rhs);
- update_stmt (gsi_stmt (*gsi));
- widen_mul_stats.maccs_inserted++;
- return true;
-}
-
-/* Given a result MUL_RESULT which is a result of a multiplication of OP1 and
- OP2 and which we know is used in statements that can be, together with the
- multiplication, converted to FMAs, perform the transformation. */
-
-static void
-convert_mult_to_fma_1 (tree mul_result, tree op1, tree op2)
-{
- tree type = TREE_TYPE (mul_result);
- gimple *use_stmt;
- imm_use_iterator imm_iter;
- gcall *fma_stmt;
-
- FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, mul_result)
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- tree addop, mulop1 = op1, result = mul_result;
- bool negate_p = false;
- gimple_seq seq = NULL;
-
- if (is_gimple_debug (use_stmt))
- continue;
-
- if (is_gimple_assign (use_stmt)
- && gimple_assign_rhs_code (use_stmt) == NEGATE_EXPR)
- {
- result = gimple_assign_lhs (use_stmt);
- use_operand_p use_p;
- gimple *neguse_stmt;
- single_imm_use (gimple_assign_lhs (use_stmt), &use_p, &neguse_stmt);
- gsi_remove (&gsi, true);
- release_defs (use_stmt);
-
- use_stmt = neguse_stmt;
- gsi = gsi_for_stmt (use_stmt);
- negate_p = true;
- }
-
- tree cond, else_value, ops[3];
- tree_code code;
- if (!can_interpret_as_conditional_op_p (use_stmt, &cond, &code,
- ops, &else_value))
- gcc_unreachable ();
- addop = ops[0] == result ? ops[1] : ops[0];
-
- if (code == MINUS_EXPR)
- {
- if (ops[0] == result)
- /* a * b - c -> a * b + (-c) */
- addop = gimple_build (&seq, NEGATE_EXPR, type, addop);
- else
- /* a - b * c -> (-b) * c + a */
- negate_p = !negate_p;
- }
-
- if (negate_p)
- mulop1 = gimple_build (&seq, NEGATE_EXPR, type, mulop1);
-
- if (seq)
- gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
-
- if (cond)
- fma_stmt = gimple_build_call_internal (IFN_COND_FMA, 5, cond, mulop1,
- op2, addop, else_value);
- else
- fma_stmt = gimple_build_call_internal (IFN_FMA, 3, mulop1, op2, addop);
- gimple_set_lhs (fma_stmt, gimple_get_lhs (use_stmt));
- gimple_call_set_nothrow (fma_stmt, !stmt_can_throw_internal (cfun,
- use_stmt));
- gsi_replace (&gsi, fma_stmt, true);
- /* Follow all SSA edges so that we generate FMS, FNMA and FNMS
- regardless of where the negation occurs. */
- gimple *orig_stmt = gsi_stmt (gsi);
- if (fold_stmt (&gsi, follow_all_ssa_edges))
- {
- if (maybe_clean_or_replace_eh_stmt (orig_stmt, gsi_stmt (gsi)))
- gcc_unreachable ();
- update_stmt (gsi_stmt (gsi));
- }
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Generated FMA ");
- print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, TDF_NONE);
- fprintf (dump_file, "\n");
- }
-
- /* If the FMA result is negated in a single use, fold the negation
- too. */
- orig_stmt = gsi_stmt (gsi);
- use_operand_p use_p;
- gimple *neg_stmt;
- if (is_gimple_call (orig_stmt)
- && gimple_call_internal_p (orig_stmt)
- && gimple_call_lhs (orig_stmt)
- && TREE_CODE (gimple_call_lhs (orig_stmt)) == SSA_NAME
- && single_imm_use (gimple_call_lhs (orig_stmt), &use_p, &neg_stmt)
- && is_gimple_assign (neg_stmt)
- && gimple_assign_rhs_code (neg_stmt) == NEGATE_EXPR
- && !stmt_could_throw_p (cfun, neg_stmt))
- {
- gsi = gsi_for_stmt (neg_stmt);
- if (fold_stmt (&gsi, follow_all_ssa_edges))
- {
- if (maybe_clean_or_replace_eh_stmt (neg_stmt, gsi_stmt (gsi)))
- gcc_unreachable ();
- update_stmt (gsi_stmt (gsi));
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Folded FMA negation ");
- print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, TDF_NONE);
- fprintf (dump_file, "\n");
- }
- }
- }
-
- widen_mul_stats.fmas_inserted++;
- }
-}
-
-/* Data necessary to perform the actual transformation from a multiplication
- and an addition to an FMA after decision is taken it should be done and to
- then delete the multiplication statement from the function IL. */
-
-struct fma_transformation_info
-{
- gimple *mul_stmt;
- tree mul_result;
- tree op1;
- tree op2;
-};
-
-/* Structure containing the current state of FMA deferring, i.e. whether we are
- deferring, whether to continue deferring, and all data necessary to come
- back and perform all deferred transformations. */
-
-class fma_deferring_state
-{
-public:
- /* Class constructor. Pass true as PERFORM_DEFERRING in order to actually
- do any deferring. */
-
- fma_deferring_state (bool perform_deferring)
- : m_candidates (), m_mul_result_set (), m_initial_phi (NULL),
- m_last_result (NULL_TREE), m_deferring_p (perform_deferring) {}
-
- /* List of FMA candidates for which we the transformation has been determined
- possible but we at this point in BB analysis we do not consider them
- beneficial. */
- auto_vec<fma_transformation_info, 8> m_candidates;
-
- /* Set of results of multiplication that are part of an already deferred FMA
- candidates. */
- hash_set<tree> m_mul_result_set;
-
- /* The PHI that supposedly feeds back result of a FMA to another over loop
- boundary. */
- gphi *m_initial_phi;
-
- /* Result of the last produced FMA candidate or NULL if there has not been
- one. */
- tree m_last_result;
-
- /* If true, deferring might still be profitable. If false, transform all
- candidates and no longer defer. */
- bool m_deferring_p;
-};
-
-/* Transform all deferred FMA candidates and mark STATE as no longer
- deferring. */
-
-static void
-cancel_fma_deferring (fma_deferring_state *state)
-{
- if (!state->m_deferring_p)
- return;
-
- for (unsigned i = 0; i < state->m_candidates.length (); i++)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Generating deferred FMA\n");
-
- const fma_transformation_info &fti = state->m_candidates[i];
- convert_mult_to_fma_1 (fti.mul_result, fti.op1, fti.op2);
-
- gimple_stmt_iterator gsi = gsi_for_stmt (fti.mul_stmt);
- gsi_remove (&gsi, true);
- release_defs (fti.mul_stmt);
- }
- state->m_deferring_p = false;
-}
-
-/* If OP is an SSA name defined by a PHI node, return the PHI statement.
- Otherwise return NULL. */
-
-static gphi *
-result_of_phi (tree op)
-{
- if (TREE_CODE (op) != SSA_NAME)
- return NULL;
-
- return dyn_cast <gphi *> (SSA_NAME_DEF_STMT (op));
-}
-
-/* After processing statements of a BB and recording STATE, return true if the
- initial phi is fed by the last FMA candidate result ore one such result from
- previously processed BBs marked in LAST_RESULT_SET. */
-
-static bool
-last_fma_candidate_feeds_initial_phi (fma_deferring_state *state,
- hash_set<tree> *last_result_set)
-{
- ssa_op_iter iter;
- use_operand_p use;
- FOR_EACH_PHI_ARG (use, state->m_initial_phi, iter, SSA_OP_USE)
- {
- tree t = USE_FROM_PTR (use);
- if (t == state->m_last_result
- || last_result_set->contains (t))
- return true;
- }
-
- return false;
-}
-
-/* Combine the multiplication at MUL_STMT with operands MULOP1 and MULOP2
- with uses in additions and subtractions to form fused multiply-add
- operations. Returns true if successful and MUL_STMT should be removed.
- If MUL_COND is nonnull, the multiplication in MUL_STMT is conditional
- on MUL_COND, otherwise it is unconditional.
-
- If STATE indicates that we are deferring FMA transformation, that means
- that we do not produce FMAs for basic blocks which look like:
-
- <bb 6>
- # accumulator_111 = PHI <0.0(5), accumulator_66(6)>
- _65 = _14 * _16;
- accumulator_66 = _65 + accumulator_111;
-
- or its unrolled version, i.e. with several FMA candidates that feed result
- of one into the addend of another. Instead, we add them to a list in STATE
- and if we later discover an FMA candidate that is not part of such a chain,
- we go back and perform all deferred past candidates. */
-
-static bool
-convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
- fma_deferring_state *state, tree mul_cond = NULL_TREE)
-{
- tree mul_result = gimple_get_lhs (mul_stmt);
- /* If there isn't a LHS then this can't be an FMA. There can be no LHS
- if the statement was left just for the side-effects. */
- if (!mul_result)
- return false;
- tree type = TREE_TYPE (mul_result);
- gimple *use_stmt, *neguse_stmt;
- use_operand_p use_p;
- imm_use_iterator imm_iter;
-
- if (FLOAT_TYPE_P (type)
- && flag_fp_contract_mode == FP_CONTRACT_OFF)
- return false;
-
- /* We don't want to do bitfield reduction ops. */
- if (INTEGRAL_TYPE_P (type)
- && (!type_has_mode_precision_p (type) || TYPE_OVERFLOW_TRAPS (type)))
- return false;
-
- /* If the target doesn't support it, don't generate it. We assume that
- if fma isn't available then fms, fnma or fnms are not either. */
- optimization_type opt_type = bb_optimization_type (gimple_bb (mul_stmt));
- if (!direct_internal_fn_supported_p (IFN_FMA, type, opt_type))
- return false;
-
- /* If the multiplication has zero uses, it is kept around probably because
- of -fnon-call-exceptions. Don't optimize it away in that case,
- it is DCE job. */
- if (has_zero_uses (mul_result))
- return false;
-
- bool check_defer
- = (state->m_deferring_p
- && maybe_le (tree_to_poly_int64 (TYPE_SIZE (type)),
- param_avoid_fma_max_bits));
- bool defer = check_defer;
- bool seen_negate_p = false;
- /* Make sure that the multiplication statement becomes dead after
- the transformation, thus that all uses are transformed to FMAs.
- This means we assume that an FMA operation has the same cost
- as an addition. */
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, mul_result)
- {
- tree result = mul_result;
- bool negate_p = false;
-
- use_stmt = USE_STMT (use_p);
-
- if (is_gimple_debug (use_stmt))
- continue;
-
- /* For now restrict this operations to single basic blocks. In theory
- we would want to support sinking the multiplication in
- m = a*b;
- if ()
- ma = m + c;
- else
- d = m;
- to form a fma in the then block and sink the multiplication to the
- else block. */
- if (gimple_bb (use_stmt) != gimple_bb (mul_stmt))
- return false;
-
- /* A negate on the multiplication leads to FNMA. */
- if (is_gimple_assign (use_stmt)
- && gimple_assign_rhs_code (use_stmt) == NEGATE_EXPR)
- {
- ssa_op_iter iter;
- use_operand_p usep;
-
- /* If (due to earlier missed optimizations) we have two
- negates of the same value, treat them as equivalent
- to a single negate with multiple uses. */
- if (seen_negate_p)
- return false;
-
- result = gimple_assign_lhs (use_stmt);
-
- /* Make sure the negate statement becomes dead with this
- single transformation. */
- if (!single_imm_use (gimple_assign_lhs (use_stmt),
- &use_p, &neguse_stmt))
- return false;
-
- /* Make sure the multiplication isn't also used on that stmt. */
- FOR_EACH_PHI_OR_STMT_USE (usep, neguse_stmt, iter, SSA_OP_USE)
- if (USE_FROM_PTR (usep) == mul_result)
- return false;
-
- /* Re-validate. */
- use_stmt = neguse_stmt;
- if (gimple_bb (use_stmt) != gimple_bb (mul_stmt))
- return false;
-
- negate_p = seen_negate_p = true;
- }
-
- tree cond, else_value, ops[3];
- tree_code code;
- if (!can_interpret_as_conditional_op_p (use_stmt, &cond, &code, ops,
- &else_value))
- return false;
-
- switch (code)
- {
- case MINUS_EXPR:
- if (ops[1] == result)
- negate_p = !negate_p;
- break;
- case PLUS_EXPR:
- break;
- default:
- /* FMA can only be formed from PLUS and MINUS. */
- return false;
- }
-
- if (mul_cond && cond != mul_cond)
- return false;
-
- if (cond)
- {
- if (cond == result || else_value == result)
- return false;
- if (!direct_internal_fn_supported_p (IFN_COND_FMA, type, opt_type))
- return false;
- }
-
- /* If the subtrahend (OPS[1]) is computed by a MULT_EXPR that
- we'll visit later, we might be able to get a more profitable
- match with fnma.
- OTOH, if we don't, a negate / fma pair has likely lower latency
- that a mult / subtract pair. */
- if (code == MINUS_EXPR
- && !negate_p
- && ops[0] == result
- && !direct_internal_fn_supported_p (IFN_FMS, type, opt_type)
- && direct_internal_fn_supported_p (IFN_FNMA, type, opt_type)
- && TREE_CODE (ops[1]) == SSA_NAME
- && has_single_use (ops[1]))
- {
- gimple *stmt2 = SSA_NAME_DEF_STMT (ops[1]);
- if (is_gimple_assign (stmt2)
- && gimple_assign_rhs_code (stmt2) == MULT_EXPR)
- return false;
- }
-
- /* We can't handle a * b + a * b. */
- if (ops[0] == ops[1])
- return false;
- /* If deferring, make sure we are not looking at an instruction that
- wouldn't have existed if we were not. */
- if (state->m_deferring_p
- && (state->m_mul_result_set.contains (ops[0])
- || state->m_mul_result_set.contains (ops[1])))
- return false;
-
- if (check_defer)
- {
- tree use_lhs = gimple_get_lhs (use_stmt);
- if (state->m_last_result)
- {
- if (ops[1] == state->m_last_result
- || ops[0] == state->m_last_result)
- defer = true;
- else
- defer = false;
- }
- else
- {
- gcc_checking_assert (!state->m_initial_phi);
- gphi *phi;
- if (ops[0] == result)
- phi = result_of_phi (ops[1]);
- else
- {
- gcc_assert (ops[1] == result);
- phi = result_of_phi (ops[0]);
- }
-
- if (phi)
- {
- state->m_initial_phi = phi;
- defer = true;
- }
- else
- defer = false;
- }
-
- state->m_last_result = use_lhs;
- check_defer = false;
- }
- else
- defer = false;
-
- /* While it is possible to validate whether or not the exact form that
- we've recognized is available in the backend, the assumption is that
- if the deferring logic above did not trigger, the transformation is
- never a loss. For instance, suppose the target only has the plain FMA
- pattern available. Consider a*b-c -> fma(a,b,-c): we've exchanged
- MUL+SUB for FMA+NEG, which is still two operations. Consider
- -(a*b)-c -> fma(-a,b,-c): we still have 3 operations, but in the FMA
- form the two NEGs are independent and could be run in parallel. */
- }
-
- if (defer)
- {
- fma_transformation_info fti;
- fti.mul_stmt = mul_stmt;
- fti.mul_result = mul_result;
- fti.op1 = op1;
- fti.op2 = op2;
- state->m_candidates.safe_push (fti);
- state->m_mul_result_set.add (mul_result);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Deferred generating FMA for multiplication ");
- print_gimple_stmt (dump_file, mul_stmt, 0, TDF_NONE);
- fprintf (dump_file, "\n");
- }
-
- return false;
- }
- else
- {
- if (state->m_deferring_p)
- cancel_fma_deferring (state);
- convert_mult_to_fma_1 (mul_result, op1, op2);
- return true;
- }
-}
-
-
-/* Helper function of match_arith_overflow. For MUL_OVERFLOW, if we have
- a check for non-zero like:
- _1 = x_4(D) * y_5(D);
- *res_7(D) = _1;
- if (x_4(D) != 0)
- goto <bb 3>; [50.00%]
- else
- goto <bb 4>; [50.00%]
-
- <bb 3> [local count: 536870913]:
- _2 = _1 / x_4(D);
- _9 = _2 != y_5(D);
- _10 = (int) _9;
-
- <bb 4> [local count: 1073741824]:
- # iftmp.0_3 = PHI <_10(3), 0(2)>
- then in addition to using .MUL_OVERFLOW (x_4(D), y_5(D)) we can also
- optimize the x_4(D) != 0 condition to 1. */
-
-static void
-maybe_optimize_guarding_check (vec<gimple *> &mul_stmts, gimple *cond_stmt,
- gimple *div_stmt, bool *cfg_changed)
-{
- basic_block bb = gimple_bb (cond_stmt);
- if (gimple_bb (div_stmt) != bb || !single_pred_p (bb))
- return;
- edge pred_edge = single_pred_edge (bb);
- basic_block pred_bb = pred_edge->src;
- if (EDGE_COUNT (pred_bb->succs) != 2)
- return;
- edge other_edge = EDGE_SUCC (pred_bb, EDGE_SUCC (pred_bb, 0) == pred_edge);
- edge other_succ_edge = NULL;
- if (gimple_code (cond_stmt) == GIMPLE_COND)
- {
- if (EDGE_COUNT (bb->succs) != 2)
- return;
- other_succ_edge = EDGE_SUCC (bb, 0);
- if (gimple_cond_code (cond_stmt) == NE_EXPR)
- {
- if (other_succ_edge->flags & EDGE_TRUE_VALUE)
- other_succ_edge = EDGE_SUCC (bb, 1);
- }
- else if (other_succ_edge->flags & EDGE_FALSE_VALUE)
- other_succ_edge = EDGE_SUCC (bb, 0);
- if (other_edge->dest != other_succ_edge->dest)
- return;
- }
- else if (!single_succ_p (bb) || other_edge->dest != single_succ (bb))
- return;
- gimple *zero_cond = last_stmt (pred_bb);
- if (zero_cond == NULL
- || gimple_code (zero_cond) != GIMPLE_COND
- || (gimple_cond_code (zero_cond)
- != ((pred_edge->flags & EDGE_TRUE_VALUE) ? NE_EXPR : EQ_EXPR))
- || !integer_zerop (gimple_cond_rhs (zero_cond)))
- return;
- tree zero_cond_lhs = gimple_cond_lhs (zero_cond);
- if (TREE_CODE (zero_cond_lhs) != SSA_NAME)
- return;
- if (gimple_assign_rhs2 (div_stmt) != zero_cond_lhs)
- {
- /* Allow the divisor to be result of a same precision cast
- from zero_cond_lhs. */
- tree rhs2 = gimple_assign_rhs2 (div_stmt);
- if (TREE_CODE (rhs2) != SSA_NAME)
- return;
- gimple *g = SSA_NAME_DEF_STMT (rhs2);
- if (!gimple_assign_cast_p (g)
- || gimple_assign_rhs1 (g) != gimple_cond_lhs (zero_cond)
- || !INTEGRAL_TYPE_P (TREE_TYPE (zero_cond_lhs))
- || (TYPE_PRECISION (TREE_TYPE (zero_cond_lhs))
- != TYPE_PRECISION (TREE_TYPE (rhs2))))
- return;
- }
- gimple_stmt_iterator gsi = gsi_after_labels (bb);
- mul_stmts.quick_push (div_stmt);
- if (is_gimple_debug (gsi_stmt (gsi)))
- gsi_next_nondebug (&gsi);
- unsigned cast_count = 0;
- while (gsi_stmt (gsi) != cond_stmt)
- {
- /* If original mul_stmt has a single use, allow it in the same bb,
- we are looking then just at __builtin_mul_overflow_p.
- Though, in that case the original mul_stmt will be replaced
- by .MUL_OVERFLOW, REALPART_EXPR and IMAGPART_EXPR stmts. */
- gimple *mul_stmt;
- unsigned int i;
- bool ok = false;
- FOR_EACH_VEC_ELT (mul_stmts, i, mul_stmt)
- {
- if (gsi_stmt (gsi) == mul_stmt)
- {
- ok = true;
- break;
- }
- }
- if (!ok && gimple_assign_cast_p (gsi_stmt (gsi)) && ++cast_count < 4)
- ok = true;
- if (!ok)
- return;
- gsi_next_nondebug (&gsi);
- }
- if (gimple_code (cond_stmt) == GIMPLE_COND)
- {
- basic_block succ_bb = other_edge->dest;
- for (gphi_iterator gpi = gsi_start_phis (succ_bb); !gsi_end_p (gpi);
- gsi_next (&gpi))
- {
- gphi *phi = gpi.phi ();
- tree v1 = gimple_phi_arg_def (phi, other_edge->dest_idx);
- tree v2 = gimple_phi_arg_def (phi, other_succ_edge->dest_idx);
- if (!operand_equal_p (v1, v2, 0))
- return;
- }
- }
- else
- {
- tree lhs = gimple_assign_lhs (cond_stmt);
- if (!lhs || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
- return;
- gsi_next_nondebug (&gsi);
- if (!gsi_end_p (gsi))
- {
- if (gimple_assign_rhs_code (cond_stmt) == COND_EXPR)
- return;
- gimple *cast_stmt = gsi_stmt (gsi);
- if (!gimple_assign_cast_p (cast_stmt))
- return;
- tree new_lhs = gimple_assign_lhs (cast_stmt);
- gsi_next_nondebug (&gsi);
- if (!gsi_end_p (gsi)
- || !new_lhs
- || !INTEGRAL_TYPE_P (TREE_TYPE (new_lhs))
- || TYPE_PRECISION (TREE_TYPE (new_lhs)) <= 1)
- return;
- lhs = new_lhs;
- }
- edge succ_edge = single_succ_edge (bb);
- basic_block succ_bb = succ_edge->dest;
- gsi = gsi_start_phis (succ_bb);
- if (gsi_end_p (gsi))
- return;
- gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
- gsi_next (&gsi);
- if (!gsi_end_p (gsi))
- return;
- if (gimple_phi_arg_def (phi, succ_edge->dest_idx) != lhs)
- return;
- tree other_val = gimple_phi_arg_def (phi, other_edge->dest_idx);
- if (gimple_assign_rhs_code (cond_stmt) == COND_EXPR)
- {
- tree cond = gimple_assign_rhs1 (cond_stmt);
- if (TREE_CODE (cond) == NE_EXPR)
- {
- if (!operand_equal_p (other_val,
- gimple_assign_rhs3 (cond_stmt), 0))
- return;
- }
- else if (!operand_equal_p (other_val,
- gimple_assign_rhs2 (cond_stmt), 0))
- return;
- }
- else if (gimple_assign_rhs_code (cond_stmt) == NE_EXPR)
- {
- if (!integer_zerop (other_val))
- return;
- }
- else if (!integer_onep (other_val))
- return;
- }
- gcond *zero_gcond = as_a <gcond *> (zero_cond);
- if (pred_edge->flags & EDGE_TRUE_VALUE)
- gimple_cond_make_true (zero_gcond);
- else
- gimple_cond_make_false (zero_gcond);
- update_stmt (zero_cond);
- *cfg_changed = true;
-}
-
-/* Helper function for arith_overflow_check_p. Return true
- if VAL1 is equal to VAL2 cast to corresponding integral type
- with other signedness or vice versa. */
-
-static bool
-arith_cast_equal_p (tree val1, tree val2)
-{
- if (TREE_CODE (val1) == INTEGER_CST && TREE_CODE (val2) == INTEGER_CST)
- return wi::eq_p (wi::to_wide (val1), wi::to_wide (val2));
- else if (TREE_CODE (val1) != SSA_NAME || TREE_CODE (val2) != SSA_NAME)
- return false;
- if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val1))
- && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val1)) == val2)
- return true;
- if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val2))
- && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val2)) == val1)
- return true;
- return false;
-}
-
-/* Helper function of match_arith_overflow. Return 1
- if USE_STMT is unsigned overflow check ovf != 0 for
- STMT, -1 if USE_STMT is unsigned overflow check ovf == 0
- and 0 otherwise. */
-
-static int
-arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
- tree maxval, tree *other)
-{
- enum tree_code ccode = ERROR_MARK;
- tree crhs1 = NULL_TREE, crhs2 = NULL_TREE;
- enum tree_code code = gimple_assign_rhs_code (stmt);
- tree lhs = gimple_assign_lhs (cast_stmt ? cast_stmt : stmt);
- tree rhs1 = gimple_assign_rhs1 (stmt);
- tree rhs2 = gimple_assign_rhs2 (stmt);
- tree multop = NULL_TREE, divlhs = NULL_TREE;
- gimple *cur_use_stmt = use_stmt;
-
- if (code == MULT_EXPR)
- {
- if (!is_gimple_assign (use_stmt))
- return 0;
- if (gimple_assign_rhs_code (use_stmt) != TRUNC_DIV_EXPR)
- return 0;
- if (gimple_assign_rhs1 (use_stmt) != lhs)
- return 0;
- if (cast_stmt)
- {
- if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs1))
- multop = rhs2;
- else if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs2))
- multop = rhs1;
- else
- return 0;
- }
- else if (gimple_assign_rhs2 (use_stmt) == rhs1)
- multop = rhs2;
- else if (operand_equal_p (gimple_assign_rhs2 (use_stmt), rhs2, 0))
- multop = rhs1;
- else
- return 0;
- if (stmt_ends_bb_p (use_stmt))
- return 0;
- divlhs = gimple_assign_lhs (use_stmt);
- if (!divlhs)
- return 0;
- use_operand_p use;
- if (!single_imm_use (divlhs, &use, &cur_use_stmt))
- return 0;
- }
- if (gimple_code (cur_use_stmt) == GIMPLE_COND)
- {
- ccode = gimple_cond_code (cur_use_stmt);
- crhs1 = gimple_cond_lhs (cur_use_stmt);
- crhs2 = gimple_cond_rhs (cur_use_stmt);
- }
- else if (is_gimple_assign (cur_use_stmt))
- {
- if (gimple_assign_rhs_class (cur_use_stmt) == GIMPLE_BINARY_RHS)
- {
- ccode = gimple_assign_rhs_code (cur_use_stmt);
- crhs1 = gimple_assign_rhs1 (cur_use_stmt);
- crhs2 = gimple_assign_rhs2 (cur_use_stmt);
- }
- else if (gimple_assign_rhs_code (cur_use_stmt) == COND_EXPR)
- {
- tree cond = gimple_assign_rhs1 (cur_use_stmt);
- if (COMPARISON_CLASS_P (cond))
- {
- ccode = TREE_CODE (cond);
- crhs1 = TREE_OPERAND (cond, 0);
- crhs2 = TREE_OPERAND (cond, 1);
- }
- else
- return 0;
- }
- else
- return 0;
- }
- else
- return 0;
-
- if (TREE_CODE_CLASS (ccode) != tcc_comparison)
- return 0;
-
- switch (ccode)
- {
- case GT_EXPR:
- case LE_EXPR:
- if (maxval)
- {
- /* r = a + b; r > maxval or r <= maxval */
- if (crhs1 == lhs
- && TREE_CODE (crhs2) == INTEGER_CST
- && tree_int_cst_equal (crhs2, maxval))
- return ccode == GT_EXPR ? 1 : -1;
- break;
- }
- /* r = a - b; r > a or r <= a
- r = a + b; a > r or a <= r or b > r or b <= r. */
- if ((code == MINUS_EXPR && crhs1 == lhs && crhs2 == rhs1)
- || (code == PLUS_EXPR && (crhs1 == rhs1 || crhs1 == rhs2)
- && crhs2 == lhs))
- return ccode == GT_EXPR ? 1 : -1;
- /* r = ~a; b > r or b <= r. */
- if (code == BIT_NOT_EXPR && crhs2 == lhs)
- {
- if (other)
- *other = crhs1;
- return ccode == GT_EXPR ? 1 : -1;
- }
- break;
- case LT_EXPR:
- case GE_EXPR:
- if (maxval)
- break;
- /* r = a - b; a < r or a >= r
- r = a + b; r < a or r >= a or r < b or r >= b. */
- if ((code == MINUS_EXPR && crhs1 == rhs1 && crhs2 == lhs)
- || (code == PLUS_EXPR && crhs1 == lhs
- && (crhs2 == rhs1 || crhs2 == rhs2)))
- return ccode == LT_EXPR ? 1 : -1;
- /* r = ~a; r < b or r >= b. */
- if (code == BIT_NOT_EXPR && crhs1 == lhs)
- {
- if (other)
- *other = crhs2;
- return ccode == LT_EXPR ? 1 : -1;
- }
- break;
- case EQ_EXPR:
- case NE_EXPR:
- /* r = a * b; _1 = r / a; _1 == b
- r = a * b; _1 = r / b; _1 == a
- r = a * b; _1 = r / a; _1 != b
- r = a * b; _1 = r / b; _1 != a. */
- if (code == MULT_EXPR)
- {
- if (cast_stmt)
- {
- if ((crhs1 == divlhs && arith_cast_equal_p (crhs2, multop))
- || (crhs2 == divlhs && arith_cast_equal_p (crhs1, multop)))
- {
- use_stmt = cur_use_stmt;
- return ccode == NE_EXPR ? 1 : -1;
- }
- }
- else if ((crhs1 == divlhs && operand_equal_p (crhs2, multop, 0))
- || (crhs2 == divlhs && crhs1 == multop))
- {
- use_stmt = cur_use_stmt;
- return ccode == NE_EXPR ? 1 : -1;
- }
- }
- break;
- default:
- break;
- }
- return 0;
-}
-
-/* Recognize for unsigned x
- x = y - z;
- if (x > y)
- where there are other uses of x and replace it with
- _7 = .SUB_OVERFLOW (y, z);
- x = REALPART_EXPR <_7>;
- _8 = IMAGPART_EXPR <_7>;
- if (_8)
- and similarly for addition.
-
- Also recognize:
- yc = (type) y;
- zc = (type) z;
- x = yc + zc;
- if (x > max)
- where y and z have unsigned types with maximum max
- and there are other uses of x and all of those cast x
- back to that unsigned type and again replace it with
- _7 = .ADD_OVERFLOW (y, z);
- _9 = REALPART_EXPR <_7>;
- _8 = IMAGPART_EXPR <_7>;
- if (_8)
- and replace (utype) x with _9.
-
- Also recognize:
- x = ~z;
- if (y > x)
- and replace it with
- _7 = .ADD_OVERFLOW (y, z);
- _8 = IMAGPART_EXPR <_7>;
- if (_8)
-
- And also recognize:
- z = x * y;
- if (x != 0)
- goto <bb 3>; [50.00%]
- else
- goto <bb 4>; [50.00%]
-
- <bb 3> [local count: 536870913]:
- _2 = z / x;
- _9 = _2 != y;
- _10 = (int) _9;
-
- <bb 4> [local count: 1073741824]:
- # iftmp.0_3 = PHI <_10(3), 0(2)>
- and replace it with
- _7 = .MUL_OVERFLOW (x, y);
- z = IMAGPART_EXPR <_7>;
- _8 = IMAGPART_EXPR <_7>;
- _9 = _8 != 0;
- iftmp.0_3 = (int) _9; */
-
-static bool
-match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
- enum tree_code code, bool *cfg_changed)
-{
- tree lhs = gimple_assign_lhs (stmt);
- tree type = TREE_TYPE (lhs);
- use_operand_p use_p;
- imm_use_iterator iter;
- bool use_seen = false;
- bool ovf_use_seen = false;
- gimple *use_stmt;
- gimple *add_stmt = NULL;
- bool add_first = false;
- gimple *cond_stmt = NULL;
- gimple *cast_stmt = NULL;
- tree cast_lhs = NULL_TREE;
-
- gcc_checking_assert (code == PLUS_EXPR
- || code == MINUS_EXPR
- || code == MULT_EXPR
- || code == BIT_NOT_EXPR);
- if (!INTEGRAL_TYPE_P (type)
- || !TYPE_UNSIGNED (type)
- || has_zero_uses (lhs)
- || (code != PLUS_EXPR
- && code != MULT_EXPR
- && optab_handler (code == MINUS_EXPR ? usubv4_optab : uaddv4_optab,
- TYPE_MODE (type)) == CODE_FOR_nothing))
- return false;
-
- tree rhs1 = gimple_assign_rhs1 (stmt);
- tree rhs2 = gimple_assign_rhs2 (stmt);
- FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
- {
- use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (use_stmt))
- continue;
-
- tree other = NULL_TREE;
- if (arith_overflow_check_p (stmt, NULL, use_stmt, NULL_TREE, &other))
- {
- if (code == BIT_NOT_EXPR)
- {
- gcc_assert (other);
- if (TREE_CODE (other) != SSA_NAME)
- return false;
- if (rhs2 == NULL)
- rhs2 = other;
- else
- return false;
- cond_stmt = use_stmt;
- }
- ovf_use_seen = true;
- }
- else
- {
- use_seen = true;
- if (code == MULT_EXPR
- && cast_stmt == NULL
- && gimple_assign_cast_p (use_stmt))
- {
- cast_lhs = gimple_assign_lhs (use_stmt);
- if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
- && !TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
- && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
- == TYPE_PRECISION (TREE_TYPE (lhs))))
- cast_stmt = use_stmt;
- else
- cast_lhs = NULL_TREE;
- }
- }
- if (ovf_use_seen && use_seen)
- break;
- }
-
- if (!ovf_use_seen
- && code == MULT_EXPR
- && cast_stmt)
- {
- if (TREE_CODE (rhs1) != SSA_NAME
- || (TREE_CODE (rhs2) != SSA_NAME && TREE_CODE (rhs2) != INTEGER_CST))
- return false;
- FOR_EACH_IMM_USE_FAST (use_p, iter, cast_lhs)
- {
- use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (use_stmt))
- continue;
-
- if (arith_overflow_check_p (stmt, cast_stmt, use_stmt,
- NULL_TREE, NULL))
- ovf_use_seen = true;
- }
- }
- else
- {
- cast_stmt = NULL;
- cast_lhs = NULL_TREE;
- }
-
- tree maxval = NULL_TREE;
- if (!ovf_use_seen
- || (code != MULT_EXPR && (code == BIT_NOT_EXPR ? use_seen : !use_seen))
- || (code == PLUS_EXPR
- && optab_handler (uaddv4_optab,
- TYPE_MODE (type)) == CODE_FOR_nothing)
- || (code == MULT_EXPR
- && optab_handler (cast_stmt ? mulv4_optab : umulv4_optab,
- TYPE_MODE (type)) == CODE_FOR_nothing))
- {
- if (code != PLUS_EXPR)
- return false;
- if (TREE_CODE (rhs1) != SSA_NAME
- || !gimple_assign_cast_p (SSA_NAME_DEF_STMT (rhs1)))
- return false;
- rhs1 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (rhs1));
- tree type1 = TREE_TYPE (rhs1);
- if (!INTEGRAL_TYPE_P (type1)
- || !TYPE_UNSIGNED (type1)
- || TYPE_PRECISION (type1) >= TYPE_PRECISION (type)
- || (TYPE_PRECISION (type1)
- != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type1))))
- return false;
- if (TREE_CODE (rhs2) == INTEGER_CST)
- {
- if (wi::ne_p (wi::rshift (wi::to_wide (rhs2),
- TYPE_PRECISION (type1),
- UNSIGNED), 0))
- return false;
- rhs2 = fold_convert (type1, rhs2);
- }
- else
- {
- if (TREE_CODE (rhs2) != SSA_NAME
- || !gimple_assign_cast_p (SSA_NAME_DEF_STMT (rhs2)))
- return false;
- rhs2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (rhs2));
- tree type2 = TREE_TYPE (rhs2);
- if (!INTEGRAL_TYPE_P (type2)
- || !TYPE_UNSIGNED (type2)
- || TYPE_PRECISION (type2) >= TYPE_PRECISION (type)
- || (TYPE_PRECISION (type2)
- != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type2))))
- return false;
- }
- if (TYPE_PRECISION (type1) >= TYPE_PRECISION (TREE_TYPE (rhs2)))
- type = type1;
- else
- type = TREE_TYPE (rhs2);
-
- if (TREE_CODE (type) != INTEGER_TYPE
- || optab_handler (uaddv4_optab,
- TYPE_MODE (type)) == CODE_FOR_nothing)
- return false;
-
- maxval = wide_int_to_tree (type, wi::max_value (TYPE_PRECISION (type),
- UNSIGNED));
- ovf_use_seen = false;
- use_seen = false;
- basic_block use_bb = NULL;
- FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
- {
- use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (use_stmt))
- continue;
-
- if (arith_overflow_check_p (stmt, NULL, use_stmt, maxval, NULL))
- {
- ovf_use_seen = true;
- use_bb = gimple_bb (use_stmt);
- }
- else
- {
- if (!gimple_assign_cast_p (use_stmt)
- || gimple_assign_rhs_code (use_stmt) == VIEW_CONVERT_EXPR)
- return false;
- tree use_lhs = gimple_assign_lhs (use_stmt);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
- || (TYPE_PRECISION (TREE_TYPE (use_lhs))
- > TYPE_PRECISION (type)))
- return false;
- use_seen = true;
- }
- }
- if (!ovf_use_seen)
- return false;
- if (!useless_type_conversion_p (type, TREE_TYPE (rhs1)))
- {
- if (!use_seen)
- return false;
- tree new_rhs1 = make_ssa_name (type);
- gimple *g = gimple_build_assign (new_rhs1, NOP_EXPR, rhs1);
- gsi_insert_before (gsi, g, GSI_SAME_STMT);
- rhs1 = new_rhs1;
- }
- else if (!useless_type_conversion_p (type, TREE_TYPE (rhs2)))
- {
- if (!use_seen)
- return false;
- tree new_rhs2 = make_ssa_name (type);
- gimple *g = gimple_build_assign (new_rhs2, NOP_EXPR, rhs2);
- gsi_insert_before (gsi, g, GSI_SAME_STMT);
- rhs2 = new_rhs2;
- }
- else if (!use_seen)
- {
- /* If there are no uses of the wider addition, check if
- forwprop has not created a narrower addition.
- Require it to be in the same bb as the overflow check. */
- FOR_EACH_IMM_USE_FAST (use_p, iter, rhs1)
- {
- use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (use_stmt))
- continue;
-
- if (use_stmt == stmt)
- continue;
-
- if (!is_gimple_assign (use_stmt)
- || gimple_bb (use_stmt) != use_bb
- || gimple_assign_rhs_code (use_stmt) != PLUS_EXPR)
- continue;
-
- if (gimple_assign_rhs1 (use_stmt) == rhs1)
- {
- if (!operand_equal_p (gimple_assign_rhs2 (use_stmt),
- rhs2, 0))
- continue;
- }
- else if (gimple_assign_rhs2 (use_stmt) == rhs1)
- {
- if (gimple_assign_rhs1 (use_stmt) != rhs2)
- continue;
- }
- else
- continue;
-
- add_stmt = use_stmt;
- break;
- }
- if (add_stmt == NULL)
- return false;
-
- /* If stmt and add_stmt are in the same bb, we need to find out
- which one is earlier. If they are in different bbs, we've
- checked add_stmt is in the same bb as one of the uses of the
- stmt lhs, so stmt needs to dominate add_stmt too. */
- if (gimple_bb (stmt) == gimple_bb (add_stmt))
- {
- gimple_stmt_iterator gsif = *gsi;
- gimple_stmt_iterator gsib = *gsi;
- int i;
- /* Search both forward and backward from stmt and have a small
- upper bound. */
- for (i = 0; i < 128; i++)
- {
- if (!gsi_end_p (gsib))
- {
- gsi_prev_nondebug (&gsib);
- if (gsi_stmt (gsib) == add_stmt)
- {
- add_first = true;
- break;
- }
- }
- else if (gsi_end_p (gsif))
- break;
- if (!gsi_end_p (gsif))
- {
- gsi_next_nondebug (&gsif);
- if (gsi_stmt (gsif) == add_stmt)
- break;
- }
- }
- if (i == 128)
- return false;
- if (add_first)
- *gsi = gsi_for_stmt (add_stmt);
- }
- }
- }
-
- if (code == BIT_NOT_EXPR)
- *gsi = gsi_for_stmt (cond_stmt);
-
- auto_vec<gimple *, 8> mul_stmts;
- if (code == MULT_EXPR && cast_stmt)
- {
- type = TREE_TYPE (cast_lhs);
- gimple *g = SSA_NAME_DEF_STMT (rhs1);
- if (gimple_assign_cast_p (g)
- && useless_type_conversion_p (type,
- TREE_TYPE (gimple_assign_rhs1 (g)))
- && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
- rhs1 = gimple_assign_rhs1 (g);
- else
- {
- g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs1);
- gsi_insert_before (gsi, g, GSI_SAME_STMT);
- rhs1 = gimple_assign_lhs (g);
- mul_stmts.quick_push (g);
- }
- if (TREE_CODE (rhs2) == INTEGER_CST)
- rhs2 = fold_convert (type, rhs2);
- else
- {
- g = SSA_NAME_DEF_STMT (rhs2);
- if (gimple_assign_cast_p (g)
- && useless_type_conversion_p (type,
- TREE_TYPE (gimple_assign_rhs1 (g)))
- && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
- rhs2 = gimple_assign_rhs1 (g);
- else
- {
- g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs2);
- gsi_insert_before (gsi, g, GSI_SAME_STMT);
- rhs2 = gimple_assign_lhs (g);
- mul_stmts.quick_push (g);
- }
- }
- }
- tree ctype = build_complex_type (type);
- gcall *g = gimple_build_call_internal (code == MULT_EXPR
- ? IFN_MUL_OVERFLOW
- : code != MINUS_EXPR
- ? IFN_ADD_OVERFLOW : IFN_SUB_OVERFLOW,
- 2, rhs1, rhs2);
- tree ctmp = make_ssa_name (ctype);
- gimple_call_set_lhs (g, ctmp);
- gsi_insert_before (gsi, g, GSI_SAME_STMT);
- tree new_lhs = (maxval || cast_stmt) ? make_ssa_name (type) : lhs;
- gassign *g2;
- if (code != BIT_NOT_EXPR)
- {
- g2 = gimple_build_assign (new_lhs, REALPART_EXPR,
- build1 (REALPART_EXPR, type, ctmp));
- if (maxval || cast_stmt)
- {
- gsi_insert_before (gsi, g2, GSI_SAME_STMT);
- if (add_first)
- *gsi = gsi_for_stmt (stmt);
- }
- else
- gsi_replace (gsi, g2, true);
- if (code == MULT_EXPR)
- {
- mul_stmts.quick_push (g);
- mul_stmts.quick_push (g2);
- if (cast_stmt)
- {
- g2 = gimple_build_assign (lhs, NOP_EXPR, new_lhs);
- gsi_replace (gsi, g2, true);
- mul_stmts.quick_push (g2);
- }
- }
- }
- tree ovf = make_ssa_name (type);
- g2 = gimple_build_assign (ovf, IMAGPART_EXPR,
- build1 (IMAGPART_EXPR, type, ctmp));
- if (code != BIT_NOT_EXPR)
- gsi_insert_after (gsi, g2, GSI_NEW_STMT);
- else
- gsi_insert_before (gsi, g2, GSI_SAME_STMT);
- if (code == MULT_EXPR)
- mul_stmts.quick_push (g2);
-
- FOR_EACH_IMM_USE_STMT (use_stmt, iter, cast_lhs ? cast_lhs : lhs)
- {
- if (is_gimple_debug (use_stmt))
- continue;
-
- gimple *orig_use_stmt = use_stmt;
- int ovf_use = arith_overflow_check_p (stmt, cast_stmt, use_stmt,
- maxval, NULL);
- if (ovf_use == 0)
- {
- gcc_assert (code != BIT_NOT_EXPR);
- if (maxval)
- {
- tree use_lhs = gimple_assign_lhs (use_stmt);
- gimple_assign_set_rhs1 (use_stmt, new_lhs);
- if (useless_type_conversion_p (TREE_TYPE (use_lhs),
- TREE_TYPE (new_lhs)))
- gimple_assign_set_rhs_code (use_stmt, SSA_NAME);
- update_stmt (use_stmt);
- }
- continue;
- }
- if (gimple_code (use_stmt) == GIMPLE_COND)
- {
- gcond *cond_stmt = as_a <gcond *> (use_stmt);
- gimple_cond_set_lhs (cond_stmt, ovf);
- gimple_cond_set_rhs (cond_stmt, build_int_cst (type, 0));
- gimple_cond_set_code (cond_stmt, ovf_use == 1 ? NE_EXPR : EQ_EXPR);
- }
- else
- {
- gcc_checking_assert (is_gimple_assign (use_stmt));
- if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
- {
- gimple_assign_set_rhs1 (use_stmt, ovf);
- gimple_assign_set_rhs2 (use_stmt, build_int_cst (type, 0));
- gimple_assign_set_rhs_code (use_stmt,
- ovf_use == 1 ? NE_EXPR : EQ_EXPR);
- }
- else
- {
- gcc_checking_assert (gimple_assign_rhs_code (use_stmt)
- == COND_EXPR);
- tree cond = build2 (ovf_use == 1 ? NE_EXPR : EQ_EXPR,
- boolean_type_node, ovf,
- build_int_cst (type, 0));
- gimple_assign_set_rhs1 (use_stmt, cond);
- }
- }
- update_stmt (use_stmt);
- if (code == MULT_EXPR && use_stmt != orig_use_stmt)
- {
- gimple_stmt_iterator gsi2 = gsi_for_stmt (orig_use_stmt);
- maybe_optimize_guarding_check (mul_stmts, use_stmt, orig_use_stmt,
- cfg_changed);
- gsi_remove (&gsi2, true);
- release_ssa_name (gimple_assign_lhs (orig_use_stmt));
- }
- }
- if (maxval)
- {
- gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
- gsi_remove (&gsi2, true);
- if (add_stmt)
- {
- gimple *g = gimple_build_assign (gimple_assign_lhs (add_stmt),
- new_lhs);
- gsi2 = gsi_for_stmt (add_stmt);
- gsi_replace (&gsi2, g, true);
- }
- }
- else if (code == BIT_NOT_EXPR)
- {
- *gsi = gsi_for_stmt (stmt);
- gsi_remove (gsi, true);
- release_ssa_name (lhs);
- return true;
- }
- return false;
-}
-
-/* Return true if target has support for divmod. */
-
-static bool
-target_supports_divmod_p (optab divmod_optab, optab div_optab, machine_mode mode)
-{
- /* If target supports hardware divmod insn, use it for divmod. */
- if (optab_handler (divmod_optab, mode) != CODE_FOR_nothing)
- return true;
-
- /* Check if libfunc for divmod is available. */
- rtx libfunc = optab_libfunc (divmod_optab, mode);
- if (libfunc != NULL_RTX)
- {
- /* If optab_handler exists for div_optab, perhaps in a wider mode,
- we don't want to use the libfunc even if it exists for given mode. */
- machine_mode div_mode;
- FOR_EACH_MODE_FROM (div_mode, mode)
- if (optab_handler (div_optab, div_mode) != CODE_FOR_nothing)
- return false;
-
- return targetm.expand_divmod_libfunc != NULL;
- }
-
- return false;
-}
-
-/* Check if stmt is candidate for divmod transform. */
-
-static bool
-divmod_candidate_p (gassign *stmt)
-{
- tree type = TREE_TYPE (gimple_assign_lhs (stmt));
- machine_mode mode = TYPE_MODE (type);
- optab divmod_optab, div_optab;
-
- if (TYPE_UNSIGNED (type))
- {
- divmod_optab = udivmod_optab;
- div_optab = udiv_optab;
- }
- else
- {
- divmod_optab = sdivmod_optab;
- div_optab = sdiv_optab;
- }
-
- tree op1 = gimple_assign_rhs1 (stmt);
- tree op2 = gimple_assign_rhs2 (stmt);
-
- /* Disable the transform if either is a constant, since division-by-constant
- may have specialized expansion. */
- if (CONSTANT_CLASS_P (op1))
- return false;
-
- if (CONSTANT_CLASS_P (op2))
- {
- if (integer_pow2p (op2))
- return false;
-
- if (TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT
- && TYPE_PRECISION (type) <= BITS_PER_WORD)
- return false;
-
- /* If the divisor is not power of 2 and the precision wider than
- HWI, expand_divmod punts on that, so in that case it is better
- to use divmod optab or libfunc. Similarly if choose_multiplier
- might need pre/post shifts of BITS_PER_WORD or more. */
- }
-
- /* Exclude the case where TYPE_OVERFLOW_TRAPS (type) as that should
- expand using the [su]divv optabs. */
- if (TYPE_OVERFLOW_TRAPS (type))
- return false;
-
- if (!target_supports_divmod_p (divmod_optab, div_optab, mode))
- return false;
-
- return true;
-}
-
-/* This function looks for:
- t1 = a TRUNC_DIV_EXPR b;
- t2 = a TRUNC_MOD_EXPR b;
- and transforms it to the following sequence:
- complex_tmp = DIVMOD (a, b);
- t1 = REALPART_EXPR(a);
- t2 = IMAGPART_EXPR(b);
- For conditions enabling the transform see divmod_candidate_p().
-
- The pass has three parts:
- 1) Find top_stmt which is trunc_div or trunc_mod stmt and dominates all
- other trunc_div_expr and trunc_mod_expr stmts.
- 2) Add top_stmt and all trunc_div and trunc_mod stmts dominated by top_stmt
- to stmts vector.
- 3) Insert DIVMOD call just before top_stmt and update entries in
- stmts vector to use return value of DIMOVD (REALEXPR_PART for div,
- IMAGPART_EXPR for mod). */
-
-static bool
-convert_to_divmod (gassign *stmt)
-{
- if (stmt_can_throw_internal (cfun, stmt)
- || !divmod_candidate_p (stmt))
- return false;
-
- tree op1 = gimple_assign_rhs1 (stmt);
- tree op2 = gimple_assign_rhs2 (stmt);
-
- imm_use_iterator use_iter;
- gimple *use_stmt;
- auto_vec<gimple *> stmts;
-
- gimple *top_stmt = stmt;
- basic_block top_bb = gimple_bb (stmt);
-
- /* Part 1: Try to set top_stmt to "topmost" stmt that dominates
- at-least stmt and possibly other trunc_div/trunc_mod stmts
- having same operands as stmt. */
-
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op1)
- {
- if (is_gimple_assign (use_stmt)
- && (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
- || gimple_assign_rhs_code (use_stmt) == TRUNC_MOD_EXPR)
- && operand_equal_p (op1, gimple_assign_rhs1 (use_stmt), 0)
- && operand_equal_p (op2, gimple_assign_rhs2 (use_stmt), 0))
- {
- if (stmt_can_throw_internal (cfun, use_stmt))
- continue;
-
- basic_block bb = gimple_bb (use_stmt);
-
- if (bb == top_bb)
- {
- if (gimple_uid (use_stmt) < gimple_uid (top_stmt))
- top_stmt = use_stmt;
- }
- else if (dominated_by_p (CDI_DOMINATORS, top_bb, bb))
- {
- top_bb = bb;
- top_stmt = use_stmt;
- }
- }
- }
-
- tree top_op1 = gimple_assign_rhs1 (top_stmt);
- tree top_op2 = gimple_assign_rhs2 (top_stmt);
-
- stmts.safe_push (top_stmt);
- bool div_seen = (gimple_assign_rhs_code (top_stmt) == TRUNC_DIV_EXPR);
-
- /* Part 2: Add all trunc_div/trunc_mod statements domianted by top_bb
- to stmts vector. The 2nd loop will always add stmt to stmts vector, since
- gimple_bb (top_stmt) dominates gimple_bb (stmt), so the
- 2nd loop ends up adding at-least single trunc_mod_expr stmt. */
-
- FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, top_op1)
- {
- if (is_gimple_assign (use_stmt)
- && (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
- || gimple_assign_rhs_code (use_stmt) == TRUNC_MOD_EXPR)
- && operand_equal_p (top_op1, gimple_assign_rhs1 (use_stmt), 0)
- && operand_equal_p (top_op2, gimple_assign_rhs2 (use_stmt), 0))
- {
- if (use_stmt == top_stmt
- || stmt_can_throw_internal (cfun, use_stmt)
- || !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), top_bb))
- continue;
-
- stmts.safe_push (use_stmt);
- if (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR)
- div_seen = true;
- }
- }
-
- if (!div_seen)
- return false;
-
- /* Part 3: Create libcall to internal fn DIVMOD:
- divmod_tmp = DIVMOD (op1, op2). */
-
- gcall *call_stmt = gimple_build_call_internal (IFN_DIVMOD, 2, op1, op2);
- tree res = make_temp_ssa_name (build_complex_type (TREE_TYPE (op1)),
- call_stmt, "divmod_tmp");
- gimple_call_set_lhs (call_stmt, res);
- /* We rejected throwing statements above. */
- gimple_call_set_nothrow (call_stmt, true);
-
- /* Insert the call before top_stmt. */
- gimple_stmt_iterator top_stmt_gsi = gsi_for_stmt (top_stmt);
- gsi_insert_before (&top_stmt_gsi, call_stmt, GSI_SAME_STMT);
-
- widen_mul_stats.divmod_calls_inserted++;
-
- /* Update all statements in stmts vector:
- lhs = op1 TRUNC_DIV_EXPR op2 -> lhs = REALPART_EXPR<divmod_tmp>
- lhs = op1 TRUNC_MOD_EXPR op2 -> lhs = IMAGPART_EXPR<divmod_tmp>. */
-
- for (unsigned i = 0; stmts.iterate (i, &use_stmt); ++i)
- {
- tree new_rhs;
-
- switch (gimple_assign_rhs_code (use_stmt))
- {
- case TRUNC_DIV_EXPR:
- new_rhs = fold_build1 (REALPART_EXPR, TREE_TYPE (op1), res);
- break;
-
- case TRUNC_MOD_EXPR:
- new_rhs = fold_build1 (IMAGPART_EXPR, TREE_TYPE (op1), res);
- break;
-
- default:
- gcc_unreachable ();
- }
-
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- gimple_assign_set_rhs_from_tree (&gsi, new_rhs);
- update_stmt (use_stmt);
- }
-
- return true;
-}
-
-/* Process a single gimple assignment STMT, which has a RSHIFT_EXPR as
- its rhs, and try to convert it into a MULT_HIGHPART_EXPR. The return
- value is true iff we converted the statement. */
-
-static bool
-convert_mult_to_highpart (gassign *stmt, gimple_stmt_iterator *gsi)
-{
- tree lhs = gimple_assign_lhs (stmt);
- tree stype = TREE_TYPE (lhs);
- tree sarg0 = gimple_assign_rhs1 (stmt);
- tree sarg1 = gimple_assign_rhs2 (stmt);
-
- if (TREE_CODE (stype) != INTEGER_TYPE
- || TREE_CODE (sarg1) != INTEGER_CST
- || TREE_CODE (sarg0) != SSA_NAME
- || !tree_fits_uhwi_p (sarg1)
- || !has_single_use (sarg0))
- return false;
-
- gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (sarg0));
- if (!def)
- return false;
-
- enum tree_code mcode = gimple_assign_rhs_code (def);
- if (mcode == NOP_EXPR)
- {
- tree tmp = gimple_assign_rhs1 (def);
- if (TREE_CODE (tmp) != SSA_NAME || !has_single_use (tmp))
- return false;
- def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (tmp));
- if (!def)
- return false;
- mcode = gimple_assign_rhs_code (def);
- }
-
- if (mcode != WIDEN_MULT_EXPR
- || gimple_bb (def) != gimple_bb (stmt))
- return false;
- tree mtype = TREE_TYPE (gimple_assign_lhs (def));
- if (TREE_CODE (mtype) != INTEGER_TYPE
- || TYPE_PRECISION (mtype) != TYPE_PRECISION (stype))
- return false;
-
- tree mop1 = gimple_assign_rhs1 (def);
- tree mop2 = gimple_assign_rhs2 (def);
- tree optype = TREE_TYPE (mop1);
- bool unsignedp = TYPE_UNSIGNED (optype);
- unsigned int prec = TYPE_PRECISION (optype);
-
- if (unsignedp != TYPE_UNSIGNED (mtype)
- || TYPE_PRECISION (mtype) != 2 * prec)
- return false;
-
- unsigned HOST_WIDE_INT bits = tree_to_uhwi (sarg1);
- if (bits < prec || bits >= 2 * prec)
- return false;
-
- machine_mode mode = TYPE_MODE (optype);
- optab tab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
- if (optab_handler (tab, mode) == CODE_FOR_nothing)
- return false;
-
- location_t loc = gimple_location (stmt);
- tree highpart1 = build_and_insert_binop (gsi, loc, "highparttmp",
- MULT_HIGHPART_EXPR, mop1, mop2);
- tree highpart2 = highpart1;
- tree ntype = optype;
-
- if (TYPE_UNSIGNED (stype) != TYPE_UNSIGNED (optype))
- {
- ntype = TYPE_UNSIGNED (stype) ? unsigned_type_for (optype)
- : signed_type_for (optype);
- highpart2 = build_and_insert_cast (gsi, loc, ntype, highpart1);
- }
- if (bits > prec)
- highpart2 = build_and_insert_binop (gsi, loc, "highparttmp",
- RSHIFT_EXPR, highpart2,
- build_int_cst (ntype, bits - prec));
-
- gassign *new_stmt = gimple_build_assign (lhs, NOP_EXPR, highpart2);
- gsi_replace (gsi, new_stmt, true);
-
- widen_mul_stats.highpart_mults_inserted++;
- return true;
-}
-
-/* If target has spaceship<MODE>3 expander, pattern recognize
- <bb 2> [local count: 1073741824]:
- if (a_2(D) == b_3(D))
- goto <bb 6>; [34.00%]
- else
- goto <bb 3>; [66.00%]
-
- <bb 3> [local count: 708669601]:
- if (a_2(D) < b_3(D))
- goto <bb 6>; [1.04%]
- else
- goto <bb 4>; [98.96%]
-
- <bb 4> [local count: 701299439]:
- if (a_2(D) > b_3(D))
- goto <bb 5>; [48.89%]
- else
- goto <bb 6>; [51.11%]
-
- <bb 5> [local count: 342865295]:
-
- <bb 6> [local count: 1073741824]:
- and turn it into:
- <bb 2> [local count: 1073741824]:
- _1 = .SPACESHIP (a_2(D), b_3(D));
- if (_1 == 0)
- goto <bb 6>; [34.00%]
- else
- goto <bb 3>; [66.00%]
-
- <bb 3> [local count: 708669601]:
- if (_1 == -1)
- goto <bb 6>; [1.04%]
- else
- goto <bb 4>; [98.96%]
-
- <bb 4> [local count: 701299439]:
- if (_1 == 1)
- goto <bb 5>; [48.89%]
- else
- goto <bb 6>; [51.11%]
-
- <bb 5> [local count: 342865295]:
-
- <bb 6> [local count: 1073741824]:
- so that the backend can emit optimal comparison and
- conditional jump sequence. */
-
-static void
-optimize_spaceship (gimple *stmt)
-{
- enum tree_code code = gimple_cond_code (stmt);
- if (code != EQ_EXPR && code != NE_EXPR)
- return;
- tree arg1 = gimple_cond_lhs (stmt);
- tree arg2 = gimple_cond_rhs (stmt);
- if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg1))
- || optab_handler (spaceship_optab,
- TYPE_MODE (TREE_TYPE (arg1))) == CODE_FOR_nothing
- || operand_equal_p (arg1, arg2, 0))
- return;
-
- basic_block bb0 = gimple_bb (stmt), bb1, bb2 = NULL;
- edge em1 = NULL, e1 = NULL, e2 = NULL;
- bb1 = EDGE_SUCC (bb0, 1)->dest;
- if (((EDGE_SUCC (bb0, 0)->flags & EDGE_TRUE_VALUE) != 0) ^ (code == EQ_EXPR))
- bb1 = EDGE_SUCC (bb0, 0)->dest;
-
- gimple *g = last_stmt (bb1);
- if (g == NULL
- || gimple_code (g) != GIMPLE_COND
- || !single_pred_p (bb1)
- || (operand_equal_p (gimple_cond_lhs (g), arg1, 0)
- ? !operand_equal_p (gimple_cond_rhs (g), arg2, 0)
- : (!operand_equal_p (gimple_cond_lhs (g), arg2, 0)
- || !operand_equal_p (gimple_cond_rhs (g), arg1, 0)))
- || !cond_only_block_p (bb1))
- return;
-
- enum tree_code ccode = (operand_equal_p (gimple_cond_lhs (g), arg1, 0)
- ? LT_EXPR : GT_EXPR);
- switch (gimple_cond_code (g))
- {
- case LT_EXPR:
- case LE_EXPR:
- break;
- case GT_EXPR:
- case GE_EXPR:
- ccode = ccode == LT_EXPR ? GT_EXPR : LT_EXPR;
- break;
- default:
- return;
- }
-
- for (int i = 0; i < 2; ++i)
- {
- /* With NaNs, </<=/>/>= are false, so we need to look for the
- third comparison on the false edge from whatever non-equality
- comparison the second comparison is. */
- if (HONOR_NANS (TREE_TYPE (arg1))
- && (EDGE_SUCC (bb1, i)->flags & EDGE_TRUE_VALUE) != 0)
- continue;
-
- bb2 = EDGE_SUCC (bb1, i)->dest;
- g = last_stmt (bb2);
- if (g == NULL
- || gimple_code (g) != GIMPLE_COND
- || !single_pred_p (bb2)
- || (operand_equal_p (gimple_cond_lhs (g), arg1, 0)
- ? !operand_equal_p (gimple_cond_rhs (g), arg2, 0)
- : (!operand_equal_p (gimple_cond_lhs (g), arg2, 0)
- || !operand_equal_p (gimple_cond_rhs (g), arg1, 0)))
- || !cond_only_block_p (bb2)
- || EDGE_SUCC (bb2, 0)->dest == EDGE_SUCC (bb2, 1)->dest)
- continue;
-
- enum tree_code ccode2
- = (operand_equal_p (gimple_cond_lhs (g), arg1, 0) ? LT_EXPR : GT_EXPR);
- switch (gimple_cond_code (g))
- {
- case LT_EXPR:
- case LE_EXPR:
- break;
- case GT_EXPR:
- case GE_EXPR:
- ccode2 = ccode2 == LT_EXPR ? GT_EXPR : LT_EXPR;
- break;
- default:
- continue;
- }
- if (HONOR_NANS (TREE_TYPE (arg1)) && ccode == ccode2)
- continue;
-
- if ((ccode == LT_EXPR)
- ^ ((EDGE_SUCC (bb1, i)->flags & EDGE_TRUE_VALUE) != 0))
- {
- em1 = EDGE_SUCC (bb1, 1 - i);
- e1 = EDGE_SUCC (bb2, 0);
- e2 = EDGE_SUCC (bb2, 1);
- if ((ccode2 == LT_EXPR) ^ ((e1->flags & EDGE_TRUE_VALUE) == 0))
- std::swap (e1, e2);
- }
- else
- {
- e1 = EDGE_SUCC (bb1, 1 - i);
- em1 = EDGE_SUCC (bb2, 0);
- e2 = EDGE_SUCC (bb2, 1);
- if ((ccode2 != LT_EXPR) ^ ((em1->flags & EDGE_TRUE_VALUE) == 0))
- std::swap (em1, e2);
- }
- break;
- }
-
- if (em1 == NULL)
- {
- if ((ccode == LT_EXPR)
- ^ ((EDGE_SUCC (bb1, 0)->flags & EDGE_TRUE_VALUE) != 0))
- {
- em1 = EDGE_SUCC (bb1, 1);
- e1 = EDGE_SUCC (bb1, 0);
- e2 = (e1->flags & EDGE_TRUE_VALUE) ? em1 : e1;
- }
- else
- {
- em1 = EDGE_SUCC (bb1, 0);
- e1 = EDGE_SUCC (bb1, 1);
- e2 = (e1->flags & EDGE_TRUE_VALUE) ? em1 : e1;
- }
- }
-
- g = gimple_build_call_internal (IFN_SPACESHIP, 2, arg1, arg2);
- tree lhs = make_ssa_name (integer_type_node);
- gimple_call_set_lhs (g, lhs);
- gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
- gsi_insert_before (&gsi, g, GSI_SAME_STMT);
-
- gcond *cond = as_a <gcond *> (stmt);
- gimple_cond_set_lhs (cond, lhs);
- gimple_cond_set_rhs (cond, integer_zero_node);
- update_stmt (stmt);
-
- g = last_stmt (bb1);
- cond = as_a <gcond *> (g);
- gimple_cond_set_lhs (cond, lhs);
- if (em1->src == bb1 && e2 != em1)
- {
- gimple_cond_set_rhs (cond, integer_minus_one_node);
- gimple_cond_set_code (cond, (em1->flags & EDGE_TRUE_VALUE)
- ? EQ_EXPR : NE_EXPR);
- }
- else
- {
- gcc_assert (e1->src == bb1 && e2 != e1);
- gimple_cond_set_rhs (cond, integer_one_node);
- gimple_cond_set_code (cond, (e1->flags & EDGE_TRUE_VALUE)
- ? EQ_EXPR : NE_EXPR);
- }
- update_stmt (g);
-
- if (e2 != e1 && e2 != em1)
- {
- g = last_stmt (bb2);
- cond = as_a <gcond *> (g);
- gimple_cond_set_lhs (cond, lhs);
- if (em1->src == bb2)
- gimple_cond_set_rhs (cond, integer_minus_one_node);
- else
- {
- gcc_assert (e1->src == bb2);
- gimple_cond_set_rhs (cond, integer_one_node);
- }
- gimple_cond_set_code (cond,
- (e2->flags & EDGE_TRUE_VALUE) ? NE_EXPR : EQ_EXPR);
- update_stmt (g);
- }
-
- wide_int wm1 = wi::minus_one (TYPE_PRECISION (integer_type_node));
- wide_int w2 = wi::two (TYPE_PRECISION (integer_type_node));
- set_range_info (lhs, VR_RANGE, wm1, w2);
-}
-
-
-/* Find integer multiplications where the operands are extended from
- smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR
- or MULT_HIGHPART_EXPR where appropriate. */
-
-namespace {
-
-const pass_data pass_data_optimize_widening_mul =
-{
- GIMPLE_PASS, /* type */
- "widening_mul", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_WIDEN_MUL, /* tv_id */
- PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
-};
-
-class pass_optimize_widening_mul : public gimple_opt_pass
-{
-public:
- pass_optimize_widening_mul (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_optimize_widening_mul, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return flag_expensive_optimizations && optimize;
- }
-
- virtual unsigned int execute (function *);
-
-}; // class pass_optimize_widening_mul
-
-/* Walker class to perform the transformation in reverse dominance order. */
-
-class math_opts_dom_walker : public dom_walker
-{
-public:
- /* Constructor, CFG_CHANGED is a pointer to a boolean flag that will be set
- if walking modidifes the CFG. */
-
- math_opts_dom_walker (bool *cfg_changed_p)
- : dom_walker (CDI_DOMINATORS), m_last_result_set (),
- m_cfg_changed_p (cfg_changed_p) {}
-
- /* The actual actions performed in the walk. */
-
- virtual void after_dom_children (basic_block);
-
- /* Set of results of chains of multiply and add statement combinations that
- were not transformed into FMAs because of active deferring. */
- hash_set<tree> m_last_result_set;
-
- /* Pointer to a flag of the user that needs to be set if CFG has been
- modified. */
- bool *m_cfg_changed_p;
-};
-
-void
-math_opts_dom_walker::after_dom_children (basic_block bb)
-{
- gimple_stmt_iterator gsi;
-
- fma_deferring_state fma_state (param_avoid_fma_max_bits > 0);
-
- for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);)
- {
- gimple *stmt = gsi_stmt (gsi);
- enum tree_code code;
-
- if (is_gimple_assign (stmt))
- {
- code = gimple_assign_rhs_code (stmt);
- switch (code)
- {
- case MULT_EXPR:
- if (!convert_mult_to_widen (stmt, &gsi)
- && !convert_expand_mult_copysign (stmt, &gsi)
- && convert_mult_to_fma (stmt,
- gimple_assign_rhs1 (stmt),
- gimple_assign_rhs2 (stmt),
- &fma_state))
- {
- gsi_remove (&gsi, true);
- release_defs (stmt);
- continue;
- }
- match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p);
- break;
-
- case PLUS_EXPR:
- case MINUS_EXPR:
- if (!convert_plusminus_to_widen (&gsi, stmt, code))
- match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p);
- break;
-
- case BIT_NOT_EXPR:
- if (match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p))
- continue;
- break;
-
- case TRUNC_MOD_EXPR:
- convert_to_divmod (as_a<gassign *> (stmt));
- break;
-
- case RSHIFT_EXPR:
- convert_mult_to_highpart (as_a<gassign *> (stmt), &gsi);
- break;
-
- default:;
- }
- }
- else if (is_gimple_call (stmt))
- {
- switch (gimple_call_combined_fn (stmt))
- {
- CASE_CFN_POW:
- if (gimple_call_lhs (stmt)
- && TREE_CODE (gimple_call_arg (stmt, 1)) == REAL_CST
- && real_equal (&TREE_REAL_CST (gimple_call_arg (stmt, 1)),
- &dconst2)
- && convert_mult_to_fma (stmt,
- gimple_call_arg (stmt, 0),
- gimple_call_arg (stmt, 0),
- &fma_state))
- {
- unlink_stmt_vdef (stmt);
- if (gsi_remove (&gsi, true)
- && gimple_purge_dead_eh_edges (bb))
- *m_cfg_changed_p = true;
- release_defs (stmt);
- continue;
- }
- break;
-
- case CFN_COND_MUL:
- if (convert_mult_to_fma (stmt,
- gimple_call_arg (stmt, 1),
- gimple_call_arg (stmt, 2),
- &fma_state,
- gimple_call_arg (stmt, 0)))
-
- {
- gsi_remove (&gsi, true);
- release_defs (stmt);
- continue;
- }
- break;
-
- case CFN_LAST:
- cancel_fma_deferring (&fma_state);
- break;
-
- default:
- break;
- }
- }
- else if (gimple_code (stmt) == GIMPLE_COND)
- optimize_spaceship (stmt);
- gsi_next (&gsi);
- }
- if (fma_state.m_deferring_p
- && fma_state.m_initial_phi)
- {
- gcc_checking_assert (fma_state.m_last_result);
- if (!last_fma_candidate_feeds_initial_phi (&fma_state,
- &m_last_result_set))
- cancel_fma_deferring (&fma_state);
- else
- m_last_result_set.add (fma_state.m_last_result);
- }
-}
-
-
-unsigned int
-pass_optimize_widening_mul::execute (function *fun)
-{
- bool cfg_changed = false;
-
- memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
- calculate_dominance_info (CDI_DOMINATORS);
- renumber_gimple_stmt_uids (cfun);
-
- math_opts_dom_walker (&cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
- statistics_counter_event (fun, "widening multiplications inserted",
- widen_mul_stats.widen_mults_inserted);
- statistics_counter_event (fun, "widening maccs inserted",
- widen_mul_stats.maccs_inserted);
- statistics_counter_event (fun, "fused multiply-adds inserted",
- widen_mul_stats.fmas_inserted);
- statistics_counter_event (fun, "divmod calls inserted",
- widen_mul_stats.divmod_calls_inserted);
- statistics_counter_event (fun, "highpart multiplications inserted",
- widen_mul_stats.highpart_mults_inserted);
-
- return cfg_changed ? TODO_cleanup_cfg : 0;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_optimize_widening_mul (gcc::context *ctxt)
-{
- return new pass_optimize_widening_mul (ctxt);
-}