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