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/fold-const.cc | |
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/fold-const.cc')
-rw-r--r-- | gcc/fold-const.cc | 16787 |
1 files changed, 16787 insertions, 0 deletions
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc new file mode 100644 index 0000000..cfeee9e --- /dev/null +++ b/gcc/fold-const.cc @@ -0,0 +1,16787 @@ +/* Fold a constant sub-tree into a single node for C-compiler + Copyright (C) 1987-2022 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/*@@ This file should be rewritten to use an arbitrary precision + @@ representation for "struct tree_int_cst" and "struct tree_real_cst". + @@ Perhaps the routines could also be used for bc/dc, and made a lib. + @@ The routines that translate from the ap rep should + @@ warn if precision et. al. is lost. + @@ This would also make life easier when this technology is used + @@ for cross-compilers. */ + +/* The entry points in this file are fold, size_int_wide and size_binop. + + fold takes a tree as argument and returns a simplified tree. + + size_binop takes a tree code for an arithmetic operation + and two operands that are trees, and produces a tree for the + result, assuming the type comes from `sizetype'. + + size_int takes an integer value, and creates a tree constant + with type from `sizetype'. + + Note: Since the folders get called on non-gimple code as well as + gimple code, we need to handle GIMPLE tuples as well as their + corresponding tree equivalents. */ + +#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 "memmodel.h" +#include "tm_p.h" +#include "tree-ssa-operands.h" +#include "optabs-query.h" +#include "cgraph.h" +#include "diagnostic-core.h" +#include "flags.h" +#include "alias.h" +#include "fold-const.h" +#include "fold-const-call.h" +#include "stor-layout.h" +#include "calls.h" +#include "tree-iterator.h" +#include "expr.h" +#include "intl.h" +#include "langhooks.h" +#include "tree-eh.h" +#include "gimplify.h" +#include "tree-dfa.h" +#include "builtins.h" +#include "generic-match.h" +#include "gimple-fold.h" +#include "tree-into-ssa.h" +#include "md5.h" +#include "case-cfn-macros.h" +#include "stringpool.h" +#include "tree-vrp.h" +#include "tree-ssanames.h" +#include "selftest.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-vector-builder.h" +#include "vec-perm-indices.h" +#include "asan.h" +#include "gimple-range.h" + +/* Nonzero if we are folding constants inside an initializer or a C++ + manifestly-constant-evaluated context; zero otherwise. */ +int folding_initializer = 0; + +/* The following constants represent a bit based encoding of GCC's + comparison operators. This encoding simplifies transformations + on relational comparison operators, such as AND and OR. */ +enum comparison_code { + COMPCODE_FALSE = 0, + COMPCODE_LT = 1, + COMPCODE_EQ = 2, + COMPCODE_LE = 3, + COMPCODE_GT = 4, + COMPCODE_LTGT = 5, + COMPCODE_GE = 6, + COMPCODE_ORD = 7, + COMPCODE_UNORD = 8, + COMPCODE_UNLT = 9, + COMPCODE_UNEQ = 10, + COMPCODE_UNLE = 11, + COMPCODE_UNGT = 12, + COMPCODE_NE = 13, + COMPCODE_UNGE = 14, + COMPCODE_TRUE = 15 +}; + +static bool negate_expr_p (tree); +static tree negate_expr (tree); +static tree associate_trees (location_t, tree, tree, enum tree_code, tree); +static enum comparison_code comparison_to_compcode (enum tree_code); +static enum tree_code compcode_to_comparison (enum comparison_code); +static bool twoval_comparison_p (tree, tree *, tree *); +static tree eval_subst (location_t, tree, tree, tree, tree, tree); +static tree optimize_bit_field_compare (location_t, enum tree_code, + tree, tree, tree); +static bool simple_operand_p (const_tree); +static bool simple_operand_p_2 (tree); +static tree range_binop (enum tree_code, tree, tree, int, tree, int); +static tree range_predecessor (tree); +static tree range_successor (tree); +static tree fold_range_test (location_t, enum tree_code, tree, tree, tree); +static tree fold_cond_expr_with_comparison (location_t, tree, enum tree_code, + tree, tree, tree, tree); +static tree unextend (tree, int, int, tree); +static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); +static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); +static tree fold_binary_op_with_conditional_arg (location_t, + enum tree_code, tree, + tree, tree, + tree, tree, int); +static tree fold_negate_const (tree, tree); +static tree fold_not_const (const_tree, tree); +static tree fold_relational_const (enum tree_code, tree, tree, tree); +static tree fold_convert_const (enum tree_code, tree, tree); +static tree fold_view_convert_expr (tree, tree); +static tree fold_negate_expr (location_t, tree); + + +/* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION. + Otherwise, return LOC. */ + +static location_t +expr_location_or (tree t, location_t loc) +{ + location_t tloc = EXPR_LOCATION (t); + return tloc == UNKNOWN_LOCATION ? loc : tloc; +} + +/* Similar to protected_set_expr_location, but never modify x in place, + if location can and needs to be set, unshare it. */ + +static inline tree +protected_set_expr_location_unshare (tree x, location_t loc) +{ + if (CAN_HAVE_LOCATION_P (x) + && EXPR_LOCATION (x) != loc + && !(TREE_CODE (x) == SAVE_EXPR + || TREE_CODE (x) == TARGET_EXPR + || TREE_CODE (x) == BIND_EXPR)) + { + x = copy_node (x); + SET_EXPR_LOCATION (x, loc); + } + return x; +} + +/* If ARG2 divides ARG1 with zero remainder, carries out the exact + division and returns the quotient. Otherwise returns + NULL_TREE. */ + +tree +div_if_zero_remainder (const_tree arg1, const_tree arg2) +{ + widest_int quo; + + if (wi::multiple_of_p (wi::to_widest (arg1), wi::to_widest (arg2), + SIGNED, &quo)) + return wide_int_to_tree (TREE_TYPE (arg1), quo); + + return NULL_TREE; +} + +/* This is nonzero if we should defer warnings about undefined + overflow. This facility exists because these warnings are a + special case. The code to estimate loop iterations does not want + to issue any warnings, since it works with expressions which do not + occur in user code. Various bits of cleanup code call fold(), but + only use the result if it has certain characteristics (e.g., is a + constant); that code only wants to issue a warning if the result is + used. */ + +static int fold_deferring_overflow_warnings; + +/* If a warning about undefined overflow is deferred, this is the + warning. Note that this may cause us to turn two warnings into + one, but that is fine since it is sufficient to only give one + warning per expression. */ + +static const char* fold_deferred_overflow_warning; + +/* If a warning about undefined overflow is deferred, this is the + level at which the warning should be emitted. */ + +static enum warn_strict_overflow_code fold_deferred_overflow_code; + +/* Start deferring overflow warnings. We could use a stack here to + permit nested calls, but at present it is not necessary. */ + +void +fold_defer_overflow_warnings (void) +{ + ++fold_deferring_overflow_warnings; +} + +/* Stop deferring overflow warnings. If there is a pending warning, + and ISSUE is true, then issue the warning if appropriate. STMT is + the statement with which the warning should be associated (used for + location information); STMT may be NULL. CODE is the level of the + warning--a warn_strict_overflow_code value. This function will use + the smaller of CODE and the deferred code when deciding whether to + issue the warning. CODE may be zero to mean to always use the + deferred code. */ + +void +fold_undefer_overflow_warnings (bool issue, const gimple *stmt, int code) +{ + const char *warnmsg; + location_t locus; + + gcc_assert (fold_deferring_overflow_warnings > 0); + --fold_deferring_overflow_warnings; + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning != NULL + && code != 0 + && code < (int) fold_deferred_overflow_code) + fold_deferred_overflow_code = (enum warn_strict_overflow_code) code; + return; + } + + warnmsg = fold_deferred_overflow_warning; + fold_deferred_overflow_warning = NULL; + + if (!issue || warnmsg == NULL) + return; + + if (warning_suppressed_p (stmt, OPT_Wstrict_overflow)) + return; + + /* Use the smallest code level when deciding to issue the + warning. */ + if (code == 0 || code > (int) fold_deferred_overflow_code) + code = fold_deferred_overflow_code; + + if (!issue_strict_overflow_warning (code)) + return; + + if (stmt == NULL) + locus = input_location; + else + locus = gimple_location (stmt); + warning_at (locus, OPT_Wstrict_overflow, "%s", warnmsg); +} + +/* Stop deferring overflow warnings, ignoring any deferred + warnings. */ + +void +fold_undefer_and_ignore_overflow_warnings (void) +{ + fold_undefer_overflow_warnings (false, NULL, 0); +} + +/* Whether we are deferring overflow warnings. */ + +bool +fold_deferring_overflow_warnings_p (void) +{ + return fold_deferring_overflow_warnings > 0; +} + +/* This is called when we fold something based on the fact that signed + overflow is undefined. */ + +void +fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc) +{ + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning == NULL + || wc < fold_deferred_overflow_code) + { + fold_deferred_overflow_warning = gmsgid; + fold_deferred_overflow_code = wc; + } + } + else if (issue_strict_overflow_warning (wc)) + warning (OPT_Wstrict_overflow, gmsgid); +} + +/* Return true if the built-in mathematical function specified by CODE + is odd, i.e. -f(x) == f(-x). */ + +bool +negate_mathfn_p (combined_fn fn) +{ + switch (fn) + { + CASE_CFN_ASIN: + CASE_CFN_ASINH: + CASE_CFN_ATAN: + CASE_CFN_ATANH: + CASE_CFN_CASIN: + CASE_CFN_CASINH: + CASE_CFN_CATAN: + CASE_CFN_CATANH: + CASE_CFN_CBRT: + CASE_CFN_CPROJ: + CASE_CFN_CSIN: + CASE_CFN_CSINH: + CASE_CFN_CTAN: + CASE_CFN_CTANH: + CASE_CFN_ERF: + CASE_CFN_LLROUND: + CASE_CFN_LROUND: + CASE_CFN_ROUND: + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: + CASE_CFN_SIN: + CASE_CFN_SINH: + CASE_CFN_TAN: + CASE_CFN_TANH: + CASE_CFN_TRUNC: + return true; + + CASE_CFN_LLRINT: + CASE_CFN_LRINT: + CASE_CFN_NEARBYINT: + CASE_CFN_RINT: + return !flag_rounding_math; + + default: + break; + } + return false; +} + +/* Check whether we may negate an integer constant T without causing + overflow. */ + +bool +may_negate_without_overflow_p (const_tree t) +{ + tree type; + + gcc_assert (TREE_CODE (t) == INTEGER_CST); + + type = TREE_TYPE (t); + if (TYPE_UNSIGNED (type)) + return false; + + return !wi::only_sign_bit_p (wi::to_wide (t)); +} + +/* Determine whether an expression T can be cheaply negated using + the function negate_expr without introducing undefined overflow. */ + +static bool +negate_expr_p (tree t) +{ + tree type; + + if (t == 0) + return false; + + type = TREE_TYPE (t); + + STRIP_SIGN_NOPS (t); + switch (TREE_CODE (t)) + { + case INTEGER_CST: + if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)) + return true; + + /* Check that -CST will not overflow type. */ + return may_negate_without_overflow_p (t); + case BIT_NOT_EXPR: + return (INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_WRAPS (type)); + + case FIXED_CST: + return true; + + case NEGATE_EXPR: + return !TYPE_OVERFLOW_SANITIZED (type); + + case REAL_CST: + /* We want to canonicalize to positive real constants. Pretend + that only negative ones can be easily negated. */ + return REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); + + case COMPLEX_CST: + return negate_expr_p (TREE_REALPART (t)) + && negate_expr_p (TREE_IMAGPART (t)); + + case VECTOR_CST: + { + if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type)) + return true; + + /* Steps don't prevent negation. */ + unsigned int count = vector_cst_encoded_nelts (t); + for (unsigned int i = 0; i < count; ++i) + if (!negate_expr_p (VECTOR_CST_ENCODED_ELT (t, i))) + return false; + + return true; + } + + case COMPLEX_EXPR: + return negate_expr_p (TREE_OPERAND (t, 0)) + && negate_expr_p (TREE_OPERAND (t, 1)); + + case CONJ_EXPR: + return negate_expr_p (TREE_OPERAND (t, 0)); + + case PLUS_EXPR: + if (HONOR_SIGN_DEPENDENT_ROUNDING (type) + || HONOR_SIGNED_ZEROS (type) + || (ANY_INTEGRAL_TYPE_P (type) + && ! TYPE_OVERFLOW_WRAPS (type))) + return false; + /* -(A + B) -> (-B) - A. */ + if (negate_expr_p (TREE_OPERAND (t, 1))) + return true; + /* -(A + B) -> (-A) - B. */ + return negate_expr_p (TREE_OPERAND (t, 0)); + + case MINUS_EXPR: + /* We can't turn -(A-B) into B-A when we honor signed zeros. */ + return !HONOR_SIGN_DEPENDENT_ROUNDING (type) + && !HONOR_SIGNED_ZEROS (type) + && (! ANY_INTEGRAL_TYPE_P (type) + || TYPE_OVERFLOW_WRAPS (type)); + + case MULT_EXPR: + if (TYPE_UNSIGNED (type)) + break; + /* INT_MIN/n * n doesn't overflow while negating one operand it does + if n is a (negative) power of two. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (t)) + && ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) + && ! ((TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST + && (wi::popcount + (wi::abs (wi::to_wide (TREE_OPERAND (t, 0))))) != 1) + || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && (wi::popcount + (wi::abs (wi::to_wide (TREE_OPERAND (t, 1))))) != 1))) + break; + + /* Fall through. */ + + case RDIV_EXPR: + if (! HONOR_SIGN_DEPENDENT_ROUNDING (t)) + return negate_expr_p (TREE_OPERAND (t, 1)) + || negate_expr_p (TREE_OPERAND (t, 0)); + break; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + if (TYPE_UNSIGNED (type)) + break; + /* In general we can't negate A in A / B, because if A is INT_MIN and + B is not 1 we change the sign of the result. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST + && negate_expr_p (TREE_OPERAND (t, 0))) + return true; + /* In general we can't negate B in A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. */ + if (! ANY_INTEGRAL_TYPE_P (TREE_TYPE (t)) + || TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) + || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && ! integer_onep (TREE_OPERAND (t, 1)))) + return negate_expr_p (TREE_OPERAND (t, 1)); + break; + + case NOP_EXPR: + /* Negate -((double)float) as (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tree tem = strip_float_extensions (t); + if (tem != t) + return negate_expr_p (tem); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (get_call_combined_fn (t))) + return negate_expr_p (CALL_EXPR_ARG (t, 0)); + break; + + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31 for int. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (wi::to_wide (op1) == element_precision (type) - 1) + return true; + } + break; + + default: + break; + } + return false; +} + +/* Given T, an expression, return a folded tree for -T or NULL_TREE, if no + simplification is possible. + If negate_expr_p would return true for T, NULL_TREE will never be + returned. */ + +static tree +fold_negate_expr_1 (location_t loc, tree t) +{ + tree type = TREE_TYPE (t); + tree tem; + + switch (TREE_CODE (t)) + { + /* Convert - (~A) to A + 1. */ + case BIT_NOT_EXPR: + if (INTEGRAL_TYPE_P (type)) + return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0), + build_one_cst (type)); + break; + + case INTEGER_CST: + tem = fold_negate_const (t, type); + if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) + || (ANY_INTEGRAL_TYPE_P (type) + && !TYPE_OVERFLOW_TRAPS (type) + && TYPE_OVERFLOW_WRAPS (type)) + || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0) + return tem; + break; + + case POLY_INT_CST: + case REAL_CST: + case FIXED_CST: + tem = fold_negate_const (t, type); + return tem; + + case COMPLEX_CST: + { + tree rpart = fold_negate_expr (loc, TREE_REALPART (t)); + tree ipart = fold_negate_expr (loc, TREE_IMAGPART (t)); + if (rpart && ipart) + return build_complex (type, rpart, ipart); + } + break; + + case VECTOR_CST: + { + tree_vector_builder elts; + elts.new_unary_operation (type, t, true); + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) + { + tree elt = fold_negate_expr (loc, VECTOR_CST_ELT (t, i)); + if (elt == NULL_TREE) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + + case COMPLEX_EXPR: + if (negate_expr_p (t)) + return fold_build2_loc (loc, COMPLEX_EXPR, type, + fold_negate_expr (loc, TREE_OPERAND (t, 0)), + fold_negate_expr (loc, TREE_OPERAND (t, 1))); + break; + + case CONJ_EXPR: + if (negate_expr_p (t)) + return fold_build1_loc (loc, CONJ_EXPR, type, + fold_negate_expr (loc, TREE_OPERAND (t, 0))); + break; + + case NEGATE_EXPR: + if (!TYPE_OVERFLOW_SANITIZED (type)) + return TREE_OPERAND (t, 0); + break; + + case PLUS_EXPR: + if (!HONOR_SIGN_DEPENDENT_ROUNDING (type) + && !HONOR_SIGNED_ZEROS (type)) + { + /* -(A + B) -> (-B) - A. */ + if (negate_expr_p (TREE_OPERAND (t, 1))) + { + tem = negate_expr (TREE_OPERAND (t, 1)); + return fold_build2_loc (loc, MINUS_EXPR, type, + tem, TREE_OPERAND (t, 0)); + } + + /* -(A + B) -> (-A) - B. */ + if (negate_expr_p (TREE_OPERAND (t, 0))) + { + tem = negate_expr (TREE_OPERAND (t, 0)); + return fold_build2_loc (loc, MINUS_EXPR, type, + tem, TREE_OPERAND (t, 1)); + } + } + break; + + case MINUS_EXPR: + /* - (A - B) -> B - A */ + if (!HONOR_SIGN_DEPENDENT_ROUNDING (type) + && !HONOR_SIGNED_ZEROS (type)) + return fold_build2_loc (loc, MINUS_EXPR, type, + TREE_OPERAND (t, 1), TREE_OPERAND (t, 0)); + break; + + case MULT_EXPR: + if (TYPE_UNSIGNED (type)) + break; + + /* Fall through. */ + + case RDIV_EXPR: + if (! HONOR_SIGN_DEPENDENT_ROUNDING (type)) + { + tem = TREE_OPERAND (t, 1); + if (negate_expr_p (tem)) + return fold_build2_loc (loc, TREE_CODE (t), type, + TREE_OPERAND (t, 0), negate_expr (tem)); + tem = TREE_OPERAND (t, 0); + if (negate_expr_p (tem)) + return fold_build2_loc (loc, TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } + break; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + if (TYPE_UNSIGNED (type)) + break; + /* In general we can't negate A in A / B, because if A is INT_MIN and + B is not 1 we change the sign of the result. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST + && negate_expr_p (TREE_OPERAND (t, 0))) + return fold_build2_loc (loc, TREE_CODE (t), type, + negate_expr (TREE_OPERAND (t, 0)), + TREE_OPERAND (t, 1)); + /* In general we can't negate B in A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. */ + if ((! ANY_INTEGRAL_TYPE_P (TREE_TYPE (t)) + || TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) + || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && ! integer_onep (TREE_OPERAND (t, 1)))) + && negate_expr_p (TREE_OPERAND (t, 1))) + return fold_build2_loc (loc, TREE_CODE (t), type, + TREE_OPERAND (t, 0), + negate_expr (TREE_OPERAND (t, 1))); + break; + + case NOP_EXPR: + /* Convert -((double)float) into (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tem = strip_float_extensions (t); + if (tem != t && negate_expr_p (tem)) + return fold_convert_loc (loc, type, negate_expr (tem)); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (get_call_combined_fn (t)) + && negate_expr_p (CALL_EXPR_ARG (t, 0))) + { + tree fndecl, arg; + + fndecl = get_callee_fndecl (t); + arg = negate_expr (CALL_EXPR_ARG (t, 0)); + return build_call_expr_loc (loc, fndecl, 1, arg); + } + break; + + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31 for int. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (wi::to_wide (op1) == element_precision (type) - 1) + { + tree ntype = TYPE_UNSIGNED (type) + ? signed_type_for (type) + : unsigned_type_for (type); + tree temp = fold_convert_loc (loc, ntype, TREE_OPERAND (t, 0)); + temp = fold_build2_loc (loc, RSHIFT_EXPR, ntype, temp, op1); + return fold_convert_loc (loc, type, temp); + } + } + break; + + default: + break; + } + + return NULL_TREE; +} + +/* A wrapper for fold_negate_expr_1. */ + +static tree +fold_negate_expr (location_t loc, tree t) +{ + tree type = TREE_TYPE (t); + STRIP_SIGN_NOPS (t); + tree tem = fold_negate_expr_1 (loc, t); + if (tem == NULL_TREE) + return NULL_TREE; + return fold_convert_loc (loc, type, tem); +} + +/* Like fold_negate_expr, but return a NEGATE_EXPR tree, if T cannot be + negated in a simpler way. Also allow for T to be NULL_TREE, in which case + return NULL_TREE. */ + +static tree +negate_expr (tree t) +{ + tree type, tem; + location_t loc; + + if (t == NULL_TREE) + return NULL_TREE; + + loc = EXPR_LOCATION (t); + type = TREE_TYPE (t); + STRIP_SIGN_NOPS (t); + + tem = fold_negate_expr (loc, t); + if (!tem) + tem = build1_loc (loc, NEGATE_EXPR, TREE_TYPE (t), t); + return fold_convert_loc (loc, type, tem); +} + +/* Split a tree IN into a constant, literal and variable parts that could be + combined with CODE to make IN. "constant" means an expression with + TREE_CONSTANT but that isn't an actual constant. CODE must be a + commutative arithmetic operation. Store the constant part into *CONP, + the literal in *LITP and return the variable part. If a part isn't + present, set it to null. If the tree does not decompose in this way, + return the entire tree as the variable part and the other parts as null. + + If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. In that + case, we negate an operand that was subtracted. Except if it is a + literal for which we use *MINUS_LITP instead. + + If NEGATE_P is true, we are negating all of IN, again except a literal + for which we use *MINUS_LITP instead. If a variable part is of pointer + type, it is negated after converting to TYPE. This prevents us from + generating illegal MINUS pointer expression. LOC is the location of + the converted variable part. + + If IN is itself a literal or constant, return it as appropriate. + + Note that we do not guarantee that any of the three values will be the + same type as IN, but they will have the same signedness and mode. */ + +static tree +split_tree (tree in, tree type, enum tree_code code, + tree *minus_varp, tree *conp, tree *minus_conp, + tree *litp, tree *minus_litp, int negate_p) +{ + tree var = 0; + *minus_varp = 0; + *conp = 0; + *minus_conp = 0; + *litp = 0; + *minus_litp = 0; + + /* Strip any conversions that don't change the machine mode or signedness. */ + STRIP_SIGN_NOPS (in); + + if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST + || TREE_CODE (in) == FIXED_CST) + *litp = in; + else if (TREE_CODE (in) == code + || ((! FLOAT_TYPE_P (TREE_TYPE (in)) || flag_associative_math) + && ! SAT_FIXED_POINT_TYPE_P (TREE_TYPE (in)) + /* We can associate addition and subtraction together (even + though the C standard doesn't say so) for integers because + the value is not affected. For reals, the value might be + affected, so we can't. */ + && ((code == PLUS_EXPR && TREE_CODE (in) == POINTER_PLUS_EXPR) + || (code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) + || (code == MINUS_EXPR + && (TREE_CODE (in) == PLUS_EXPR + || TREE_CODE (in) == POINTER_PLUS_EXPR))))) + { + tree op0 = TREE_OPERAND (in, 0); + tree op1 = TREE_OPERAND (in, 1); + int neg1_p = TREE_CODE (in) == MINUS_EXPR; + int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0; + + /* First see if either of the operands is a literal, then a constant. */ + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST + || TREE_CODE (op0) == FIXED_CST) + *litp = op0, op0 = 0; + else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST + || TREE_CODE (op1) == FIXED_CST) + *litp = op1, neg_litp_p = neg1_p, op1 = 0; + + if (op0 != 0 && TREE_CONSTANT (op0)) + *conp = op0, op0 = 0; + else if (op1 != 0 && TREE_CONSTANT (op1)) + *conp = op1, neg_conp_p = neg1_p, op1 = 0; + + /* If we haven't dealt with either operand, this is not a case we can + decompose. Otherwise, VAR is either of the ones remaining, if any. */ + if (op0 != 0 && op1 != 0) + var = in; + else if (op0 != 0) + var = op0; + else + var = op1, neg_var_p = neg1_p; + + /* Now do any needed negations. */ + if (neg_litp_p) + *minus_litp = *litp, *litp = 0; + if (neg_conp_p && *conp) + *minus_conp = *conp, *conp = 0; + if (neg_var_p && var) + *minus_varp = var, var = 0; + } + else if (TREE_CONSTANT (in)) + *conp = in; + else if (TREE_CODE (in) == BIT_NOT_EXPR + && code == PLUS_EXPR) + { + /* -1 - X is folded to ~X, undo that here. Do _not_ do this + when IN is constant. */ + *litp = build_minus_one_cst (type); + *minus_varp = TREE_OPERAND (in, 0); + } + else + var = in; + + if (negate_p) + { + if (*litp) + *minus_litp = *litp, *litp = 0; + else if (*minus_litp) + *litp = *minus_litp, *minus_litp = 0; + if (*conp) + *minus_conp = *conp, *conp = 0; + else if (*minus_conp) + *conp = *minus_conp, *minus_conp = 0; + if (var) + *minus_varp = var, var = 0; + else if (*minus_varp) + var = *minus_varp, *minus_varp = 0; + } + + if (*litp + && TREE_OVERFLOW_P (*litp)) + *litp = drop_tree_overflow (*litp); + if (*minus_litp + && TREE_OVERFLOW_P (*minus_litp)) + *minus_litp = drop_tree_overflow (*minus_litp); + + return var; +} + +/* Re-associate trees split by the above function. T1 and T2 are + either expressions to associate or null. Return the new + expression, if any. LOC is the location of the new expression. If + we build an operation, do it in TYPE and with CODE. */ + +static tree +associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree type) +{ + if (t1 == 0) + { + gcc_assert (t2 == 0 || code != MINUS_EXPR); + return t2; + } + else if (t2 == 0) + return t1; + + /* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't + try to fold this since we will have infinite recursion. But do + deal with any NEGATE_EXPRs. */ + if (TREE_CODE (t1) == code || TREE_CODE (t2) == code + || TREE_CODE (t1) == PLUS_EXPR || TREE_CODE (t2) == PLUS_EXPR + || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR) + { + if (code == PLUS_EXPR) + { + if (TREE_CODE (t1) == NEGATE_EXPR) + return build2_loc (loc, MINUS_EXPR, type, + fold_convert_loc (loc, type, t2), + fold_convert_loc (loc, type, + TREE_OPERAND (t1, 0))); + else if (TREE_CODE (t2) == NEGATE_EXPR) + return build2_loc (loc, MINUS_EXPR, type, + fold_convert_loc (loc, type, t1), + fold_convert_loc (loc, type, + TREE_OPERAND (t2, 0))); + else if (integer_zerop (t2)) + return fold_convert_loc (loc, type, t1); + } + else if (code == MINUS_EXPR) + { + if (integer_zerop (t2)) + return fold_convert_loc (loc, type, t1); + } + + return build2_loc (loc, code, type, fold_convert_loc (loc, type, t1), + fold_convert_loc (loc, type, t2)); + } + + return fold_build2_loc (loc, code, type, fold_convert_loc (loc, type, t1), + fold_convert_loc (loc, type, t2)); +} + +/* Check whether TYPE1 and TYPE2 are equivalent integer types, suitable + for use in int_const_binop, size_binop and size_diffop. */ + +static bool +int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2) +{ + if (!INTEGRAL_TYPE_P (type1) && !POINTER_TYPE_P (type1)) + return false; + if (!INTEGRAL_TYPE_P (type2) && !POINTER_TYPE_P (type2)) + return false; + + switch (code) + { + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + return true; + + default: + break; + } + + return TYPE_UNSIGNED (type1) == TYPE_UNSIGNED (type2) + && TYPE_PRECISION (type1) == TYPE_PRECISION (type2) + && TYPE_MODE (type1) == TYPE_MODE (type2); +} + +/* Combine two wide ints ARG1 and ARG2 under operation CODE to produce + a new constant in RES. Return FALSE if we don't know how to + evaluate CODE at compile-time. */ + +bool +wide_int_binop (wide_int &res, + enum tree_code code, const wide_int &arg1, const wide_int &arg2, + signop sign, wi::overflow_type *overflow) +{ + wide_int tmp; + *overflow = wi::OVF_NONE; + switch (code) + { + case BIT_IOR_EXPR: + res = wi::bit_or (arg1, arg2); + break; + + case BIT_XOR_EXPR: + res = wi::bit_xor (arg1, arg2); + break; + + case BIT_AND_EXPR: + res = wi::bit_and (arg1, arg2); + break; + + case LSHIFT_EXPR: + if (wi::neg_p (arg2)) + return false; + res = wi::lshift (arg1, arg2); + break; + + case RSHIFT_EXPR: + if (wi::neg_p (arg2)) + return false; + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + res = wi::rshift (arg1, arg2, sign); + break; + + case RROTATE_EXPR: + case LROTATE_EXPR: + if (wi::neg_p (arg2)) + { + tmp = -arg2; + if (code == RROTATE_EXPR) + code = LROTATE_EXPR; + else + code = RROTATE_EXPR; + } + else + tmp = arg2; + + if (code == RROTATE_EXPR) + res = wi::rrotate (arg1, tmp); + else + res = wi::lrotate (arg1, tmp); + break; + + case PLUS_EXPR: + res = wi::add (arg1, arg2, sign, overflow); + break; + + case MINUS_EXPR: + res = wi::sub (arg1, arg2, sign, overflow); + break; + + case MULT_EXPR: + res = wi::mul (arg1, arg2, sign, overflow); + break; + + case MULT_HIGHPART_EXPR: + res = wi::mul_high (arg1, arg2, sign); + break; + + case TRUNC_DIV_EXPR: + case EXACT_DIV_EXPR: + if (arg2 == 0) + return false; + res = wi::div_trunc (arg1, arg2, sign, overflow); + break; + + case FLOOR_DIV_EXPR: + if (arg2 == 0) + return false; + res = wi::div_floor (arg1, arg2, sign, overflow); + break; + + case CEIL_DIV_EXPR: + if (arg2 == 0) + return false; + res = wi::div_ceil (arg1, arg2, sign, overflow); + break; + + case ROUND_DIV_EXPR: + if (arg2 == 0) + return false; + res = wi::div_round (arg1, arg2, sign, overflow); + break; + + case TRUNC_MOD_EXPR: + if (arg2 == 0) + return false; + res = wi::mod_trunc (arg1, arg2, sign, overflow); + break; + + case FLOOR_MOD_EXPR: + if (arg2 == 0) + return false; + res = wi::mod_floor (arg1, arg2, sign, overflow); + break; + + case CEIL_MOD_EXPR: + if (arg2 == 0) + return false; + res = wi::mod_ceil (arg1, arg2, sign, overflow); + break; + + case ROUND_MOD_EXPR: + if (arg2 == 0) + return false; + res = wi::mod_round (arg1, arg2, sign, overflow); + break; + + case MIN_EXPR: + res = wi::min (arg1, arg2, sign); + break; + + case MAX_EXPR: + res = wi::max (arg1, arg2, sign); + break; + + default: + return false; + } + return true; +} + +/* Combine two poly int's ARG1 and ARG2 under operation CODE to + produce a new constant in RES. Return FALSE if we don't know how + to evaluate CODE at compile-time. */ + +static bool +poly_int_binop (poly_wide_int &res, enum tree_code code, + const_tree arg1, const_tree arg2, + signop sign, wi::overflow_type *overflow) +{ + gcc_assert (NUM_POLY_INT_COEFFS != 1); + gcc_assert (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)); + switch (code) + { + case PLUS_EXPR: + res = wi::add (wi::to_poly_wide (arg1), + wi::to_poly_wide (arg2), sign, overflow); + break; + + case MINUS_EXPR: + res = wi::sub (wi::to_poly_wide (arg1), + wi::to_poly_wide (arg2), sign, overflow); + break; + + case MULT_EXPR: + if (TREE_CODE (arg2) == INTEGER_CST) + res = wi::mul (wi::to_poly_wide (arg1), + wi::to_wide (arg2), sign, overflow); + else if (TREE_CODE (arg1) == INTEGER_CST) + res = wi::mul (wi::to_poly_wide (arg2), + wi::to_wide (arg1), sign, overflow); + else + return NULL_TREE; + break; + + case LSHIFT_EXPR: + if (TREE_CODE (arg2) == INTEGER_CST) + res = wi::to_poly_wide (arg1) << wi::to_wide (arg2); + else + return false; + break; + + case BIT_IOR_EXPR: + if (TREE_CODE (arg2) != INTEGER_CST + || !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2), + &res)) + return false; + break; + + default: + return false; + } + return true; +} + +/* Combine two integer constants ARG1 and ARG2 under operation CODE to + produce a new constant. Return NULL_TREE if we don't know how to + evaluate CODE at compile-time. */ + +tree +int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2, + int overflowable) +{ + poly_wide_int poly_res; + tree type = TREE_TYPE (arg1); + signop sign = TYPE_SIGN (type); + wi::overflow_type overflow = wi::OVF_NONE; + + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST) + { + wide_int warg1 = wi::to_wide (arg1), res; + wide_int warg2 = wi::to_wide (arg2, TYPE_PRECISION (type)); + if (!wide_int_binop (res, code, warg1, warg2, sign, &overflow)) + return NULL_TREE; + poly_res = res; + } + else if (!poly_int_tree_p (arg1) + || !poly_int_tree_p (arg2) + || !poly_int_binop (poly_res, code, arg1, arg2, sign, &overflow)) + return NULL_TREE; + return force_fit_type (type, poly_res, overflowable, + (((sign == SIGNED || overflowable == -1) + && overflow) + | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))); +} + +/* Return true if binary operation OP distributes over addition in operand + OPNO, with the other operand being held constant. OPNO counts from 1. */ + +static bool +distributes_over_addition_p (tree_code op, int opno) +{ + switch (op) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + return true; + + case LSHIFT_EXPR: + return opno == 1; + + default: + return false; + } +} + +/* Combine two constants ARG1 and ARG2 under operation CODE to produce a new + constant. We assume ARG1 and ARG2 have the same data type, or at least + are the same kind of constant and the same machine mode. Return zero if + combining the constants is not allowed in the current operating mode. */ + +static tree +const_binop (enum tree_code code, tree arg1, tree arg2) +{ + /* Sanity check for the recursive cases. */ + if (!arg1 || !arg2) + return NULL_TREE; + + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + + if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)) + { + if (code == POINTER_PLUS_EXPR) + return int_const_binop (PLUS_EXPR, + arg1, fold_convert (TREE_TYPE (arg1), arg2)); + + return int_const_binop (code, arg1, arg2); + } + + if (TREE_CODE (arg1) == REAL_CST && TREE_CODE (arg2) == REAL_CST) + { + machine_mode mode; + REAL_VALUE_TYPE d1; + REAL_VALUE_TYPE d2; + REAL_VALUE_TYPE value; + REAL_VALUE_TYPE result; + bool inexact; + tree t, type; + + /* The following codes are handled by real_arithmetic. */ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case RDIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + break; + + default: + return NULL_TREE; + } + + d1 = TREE_REAL_CST (arg1); + d2 = TREE_REAL_CST (arg2); + + type = TREE_TYPE (arg1); + mode = TYPE_MODE (type); + + /* Don't perform operation if we honor signaling NaNs and + either operand is a signaling NaN. */ + if (HONOR_SNANS (mode) + && (REAL_VALUE_ISSIGNALING_NAN (d1) + || REAL_VALUE_ISSIGNALING_NAN (d2))) + return NULL_TREE; + + /* Don't perform operation if it would raise a division + by zero exception. */ + if (code == RDIV_EXPR + && real_equal (&d2, &dconst0) + && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode))) + return NULL_TREE; + + /* If either operand is a NaN, just return it. Otherwise, set up + for floating-point trap; we return an overflow. */ + if (REAL_VALUE_ISNAN (d1)) + { + /* Make resulting NaN value to be qNaN when flag_signaling_nans + is off. */ + d1.signalling = 0; + t = build_real (type, d1); + return t; + } + else if (REAL_VALUE_ISNAN (d2)) + { + /* Make resulting NaN value to be qNaN when flag_signaling_nans + is off. */ + d2.signalling = 0; + t = build_real (type, d2); + return t; + } + + inexact = real_arithmetic (&value, code, &d1, &d2); + real_convert (&result, mode, &value); + + /* Don't constant fold this floating point operation if + the result has overflowed and flag_trapping_math. */ + if (flag_trapping_math + && MODE_HAS_INFINITIES (mode) + && REAL_VALUE_ISINF (result) + && !REAL_VALUE_ISINF (d1) + && !REAL_VALUE_ISINF (d2)) + return NULL_TREE; + + /* Don't constant fold this floating point operation if the + result may dependent upon the run-time rounding mode and + flag_rounding_math is set, or if GCC's software emulation + is unable to accurately represent the result. */ + if ((flag_rounding_math + || (MODE_COMPOSITE_P (mode) && !flag_unsafe_math_optimizations)) + && (inexact || !real_identical (&result, &value))) + return NULL_TREE; + + t = build_real (type, result); + + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2); + return t; + } + + if (TREE_CODE (arg1) == FIXED_CST) + { + FIXED_VALUE_TYPE f1; + FIXED_VALUE_TYPE f2; + FIXED_VALUE_TYPE result; + tree t, type; + int sat_p; + bool overflow_p; + + /* The following codes are handled by fixed_arithmetic. */ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + if (TREE_CODE (arg2) != FIXED_CST) + return NULL_TREE; + f2 = TREE_FIXED_CST (arg2); + break; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + { + if (TREE_CODE (arg2) != INTEGER_CST) + return NULL_TREE; + wi::tree_to_wide_ref w2 = wi::to_wide (arg2); + f2.data.high = w2.elt (1); + f2.data.low = w2.ulow (); + f2.mode = SImode; + } + break; + + default: + return NULL_TREE; + } + + f1 = TREE_FIXED_CST (arg1); + type = TREE_TYPE (arg1); + sat_p = TYPE_SATURATING (type); + overflow_p = fixed_arithmetic (&result, code, &f1, &f2, sat_p); + t = build_fixed (type, result); + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)) + TREE_OVERFLOW (t) = 1; + return t; + } + + if (TREE_CODE (arg1) == COMPLEX_CST && TREE_CODE (arg2) == COMPLEX_CST) + { + tree type = TREE_TYPE (arg1); + tree r1 = TREE_REALPART (arg1); + tree i1 = TREE_IMAGPART (arg1); + tree r2 = TREE_REALPART (arg2); + tree i2 = TREE_IMAGPART (arg2); + tree real, imag; + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + real = const_binop (code, r1, r2); + imag = const_binop (code, i1, i2); + break; + + case MULT_EXPR: + if (COMPLEX_FLOAT_TYPE_P (type)) + return do_mpc_arg2 (arg1, arg2, type, + /* do_nonfinite= */ folding_initializer, + mpc_mul); + + real = const_binop (MINUS_EXPR, + const_binop (MULT_EXPR, r1, r2), + const_binop (MULT_EXPR, i1, i2)); + imag = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r1, i2), + const_binop (MULT_EXPR, i1, r2)); + break; + + case RDIV_EXPR: + if (COMPLEX_FLOAT_TYPE_P (type)) + return do_mpc_arg2 (arg1, arg2, type, + /* do_nonfinite= */ folding_initializer, + mpc_div); + /* Fallthru. */ + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + if (flag_complex_method == 0) + { + /* Keep this algorithm in sync with + tree-complex.c:expand_complex_div_straight(). + + Expand complex division to scalars, straightforward algorithm. + a / b = ((ar*br + ai*bi)/t) + i((ai*br - ar*bi)/t) + t = br*br + bi*bi + */ + tree magsquared + = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r2, r2), + const_binop (MULT_EXPR, i2, i2)); + tree t1 + = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r1, r2), + const_binop (MULT_EXPR, i1, i2)); + tree t2 + = const_binop (MINUS_EXPR, + const_binop (MULT_EXPR, i1, r2), + const_binop (MULT_EXPR, r1, i2)); + + real = const_binop (code, t1, magsquared); + imag = const_binop (code, t2, magsquared); + } + else + { + /* Keep this algorithm in sync with + tree-complex.c:expand_complex_div_wide(). + + Expand complex division to scalars, modified algorithm to minimize + overflow with wide input ranges. */ + tree compare = fold_build2 (LT_EXPR, boolean_type_node, + fold_abs_const (r2, TREE_TYPE (type)), + fold_abs_const (i2, TREE_TYPE (type))); + + if (integer_nonzerop (compare)) + { + /* In the TRUE branch, we compute + ratio = br/bi; + div = (br * ratio) + bi; + tr = (ar * ratio) + ai; + ti = (ai * ratio) - ar; + tr = tr / div; + ti = ti / div; */ + tree ratio = const_binop (code, r2, i2); + tree div = const_binop (PLUS_EXPR, i2, + const_binop (MULT_EXPR, r2, ratio)); + real = const_binop (MULT_EXPR, r1, ratio); + real = const_binop (PLUS_EXPR, real, i1); + real = const_binop (code, real, div); + + imag = const_binop (MULT_EXPR, i1, ratio); + imag = const_binop (MINUS_EXPR, imag, r1); + imag = const_binop (code, imag, div); + } + else + { + /* In the FALSE branch, we compute + ratio = d/c; + divisor = (d * ratio) + c; + tr = (b * ratio) + a; + ti = b - (a * ratio); + tr = tr / div; + ti = ti / div; */ + tree ratio = const_binop (code, i2, r2); + tree div = const_binop (PLUS_EXPR, r2, + const_binop (MULT_EXPR, i2, ratio)); + + real = const_binop (MULT_EXPR, i1, ratio); + real = const_binop (PLUS_EXPR, real, r1); + real = const_binop (code, real, div); + + imag = const_binop (MULT_EXPR, r1, ratio); + imag = const_binop (MINUS_EXPR, i1, imag); + imag = const_binop (code, imag, div); + } + } + break; + + default: + return NULL_TREE; + } + + if (real && imag) + return build_complex (type, real, imag); + } + + if (TREE_CODE (arg1) == VECTOR_CST + && TREE_CODE (arg2) == VECTOR_CST + && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)), + TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2)))) + { + tree type = TREE_TYPE (arg1); + bool step_ok_p; + if (VECTOR_CST_STEPPED_P (arg1) + && VECTOR_CST_STEPPED_P (arg2)) + /* We can operate directly on the encoding if: + + a3 - a2 == a2 - a1 && b3 - b2 == b2 - b1 + implies + (a3 op b3) - (a2 op b2) == (a2 op b2) - (a1 op b1) + + Addition and subtraction are the supported operators + for which this is true. */ + step_ok_p = (code == PLUS_EXPR || code == MINUS_EXPR); + else if (VECTOR_CST_STEPPED_P (arg1)) + /* We can operate directly on stepped encodings if: + + a3 - a2 == a2 - a1 + implies: + (a3 op c) - (a2 op c) == (a2 op c) - (a1 op c) + + which is true if (x -> x op c) distributes over addition. */ + step_ok_p = distributes_over_addition_p (code, 1); + else + /* Similarly in reverse. */ + step_ok_p = distributes_over_addition_p (code, 2); + tree_vector_builder elts; + if (!elts.new_binary_operation (type, arg1, arg2, step_ok_p)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) + { + tree elem1 = VECTOR_CST_ELT (arg1, i); + tree elem2 = VECTOR_CST_ELT (arg2, i); + + tree elt = const_binop (code, elem1, elem2); + + /* It is possible that const_binop cannot handle the given + code and return NULL_TREE */ + if (elt == NULL_TREE) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + + /* Shifts allow a scalar offset for a vector. */ + if (TREE_CODE (arg1) == VECTOR_CST + && TREE_CODE (arg2) == INTEGER_CST) + { + tree type = TREE_TYPE (arg1); + bool step_ok_p = distributes_over_addition_p (code, 1); + tree_vector_builder elts; + if (!elts.new_unary_operation (type, arg1, step_ok_p)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) + { + tree elem1 = VECTOR_CST_ELT (arg1, i); + + tree elt = const_binop (code, elem1, arg2); + + /* It is possible that const_binop cannot handle the given + code and return NULL_TREE. */ + if (elt == NULL_TREE) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + return NULL_TREE; +} + +/* Overload that adds a TYPE parameter to be able to dispatch + to fold_relational_const. */ + +tree +const_binop (enum tree_code code, tree type, tree arg1, tree arg2) +{ + if (TREE_CODE_CLASS (code) == tcc_comparison) + return fold_relational_const (code, type, arg1, arg2); + + /* ??? Until we make the const_binop worker take the type of the + result as argument put those cases that need it here. */ + switch (code) + { + case VEC_SERIES_EXPR: + if (CONSTANT_CLASS_P (arg1) + && CONSTANT_CLASS_P (arg2)) + return build_vec_series (type, arg1, arg2); + return NULL_TREE; + + case COMPLEX_EXPR: + if ((TREE_CODE (arg1) == REAL_CST + && TREE_CODE (arg2) == REAL_CST) + || (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg2) == INTEGER_CST)) + return build_complex (type, arg1, arg2); + return NULL_TREE; + + case POINTER_DIFF_EXPR: + if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)) + { + poly_offset_int res = (wi::to_poly_offset (arg1) + - wi::to_poly_offset (arg2)); + return force_fit_type (type, res, 1, + TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)); + } + return NULL_TREE; + + case VEC_PACK_TRUNC_EXPR: + case VEC_PACK_FIX_TRUNC_EXPR: + case VEC_PACK_FLOAT_EXPR: + { + unsigned int HOST_WIDE_INT out_nelts, in_nelts, i; + + if (TREE_CODE (arg1) != VECTOR_CST + || TREE_CODE (arg2) != VECTOR_CST) + return NULL_TREE; + + if (!VECTOR_CST_NELTS (arg1).is_constant (&in_nelts)) + return NULL_TREE; + + out_nelts = in_nelts * 2; + gcc_assert (known_eq (in_nelts, VECTOR_CST_NELTS (arg2)) + && known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); + + tree_vector_builder elts (type, out_nelts, 1); + for (i = 0; i < out_nelts; i++) + { + tree elt = (i < in_nelts + ? VECTOR_CST_ELT (arg1, i) + : VECTOR_CST_ELT (arg2, i - in_nelts)); + elt = fold_convert_const (code == VEC_PACK_TRUNC_EXPR + ? NOP_EXPR + : code == VEC_PACK_FLOAT_EXPR + ? FLOAT_EXPR : FIX_TRUNC_EXPR, + TREE_TYPE (type), elt); + if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + + case VEC_WIDEN_MULT_LO_EXPR: + case VEC_WIDEN_MULT_HI_EXPR: + case VEC_WIDEN_MULT_EVEN_EXPR: + case VEC_WIDEN_MULT_ODD_EXPR: + { + unsigned HOST_WIDE_INT out_nelts, in_nelts, out, ofs, scale; + + if (TREE_CODE (arg1) != VECTOR_CST || TREE_CODE (arg2) != VECTOR_CST) + return NULL_TREE; + + if (!VECTOR_CST_NELTS (arg1).is_constant (&in_nelts)) + return NULL_TREE; + out_nelts = in_nelts / 2; + gcc_assert (known_eq (in_nelts, VECTOR_CST_NELTS (arg2)) + && known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); + + if (code == VEC_WIDEN_MULT_LO_EXPR) + scale = 0, ofs = BYTES_BIG_ENDIAN ? out_nelts : 0; + else if (code == VEC_WIDEN_MULT_HI_EXPR) + scale = 0, ofs = BYTES_BIG_ENDIAN ? 0 : out_nelts; + else if (code == VEC_WIDEN_MULT_EVEN_EXPR) + scale = 1, ofs = 0; + else /* if (code == VEC_WIDEN_MULT_ODD_EXPR) */ + scale = 1, ofs = 1; + + tree_vector_builder elts (type, out_nelts, 1); + for (out = 0; out < out_nelts; out++) + { + unsigned int in = (out << scale) + ofs; + tree t1 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), + VECTOR_CST_ELT (arg1, in)); + tree t2 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), + VECTOR_CST_ELT (arg2, in)); + + if (t1 == NULL_TREE || t2 == NULL_TREE) + return NULL_TREE; + tree elt = const_binop (MULT_EXPR, t1, t2); + if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + + default:; + } + + if (TREE_CODE_CLASS (code) != tcc_binary) + return NULL_TREE; + + /* Make sure type and arg0 have the same saturating flag. */ + gcc_checking_assert (TYPE_SATURATING (type) + == TYPE_SATURATING (TREE_TYPE (arg1))); + + return const_binop (code, arg1, arg2); +} + +/* Compute CODE ARG1 with resulting type TYPE with ARG1 being constant. + Return zero if computing the constants is not possible. */ + +tree +const_unop (enum tree_code code, tree type, tree arg0) +{ + /* Don't perform the operation, other than NEGATE and ABS, if + flag_signaling_nans is on and the operand is a signaling NaN. */ + if (TREE_CODE (arg0) == REAL_CST + && HONOR_SNANS (arg0) + && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0)) + && code != NEGATE_EXPR + && code != ABS_EXPR + && code != ABSU_EXPR) + return NULL_TREE; + + switch (code) + { + CASE_CONVERT: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIXED_CONVERT_EXPR: + return fold_convert_const (code, type, arg0); + + case ADDR_SPACE_CONVERT_EXPR: + /* If the source address is 0, and the source address space + cannot have a valid object at 0, fold to dest type null. */ + if (integer_zerop (arg0) + && !(targetm.addr_space.zero_address_valid + (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))))) + return fold_convert_const (code, type, arg0); + break; + + case VIEW_CONVERT_EXPR: + return fold_view_convert_expr (type, arg0); + + case NEGATE_EXPR: + { + /* Can't call fold_negate_const directly here as that doesn't + handle all cases and we might not be able to negate some + constants. */ + tree tem = fold_negate_expr (UNKNOWN_LOCATION, arg0); + if (tem && CONSTANT_CLASS_P (tem)) + return tem; + break; + } + + case ABS_EXPR: + case ABSU_EXPR: + if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST) + return fold_abs_const (arg0, type); + break; + + case CONJ_EXPR: + if (TREE_CODE (arg0) == COMPLEX_CST) + { + tree ipart = fold_negate_const (TREE_IMAGPART (arg0), + TREE_TYPE (type)); + return build_complex (type, TREE_REALPART (arg0), ipart); + } + break; + + case BIT_NOT_EXPR: + if (TREE_CODE (arg0) == INTEGER_CST) + return fold_not_const (arg0, type); + else if (POLY_INT_CST_P (arg0)) + return wide_int_to_tree (type, -poly_int_cst_value (arg0)); + /* Perform BIT_NOT_EXPR on each element individually. */ + else if (TREE_CODE (arg0) == VECTOR_CST) + { + tree elem; + + /* This can cope with stepped encodings because ~x == -1 - x. */ + tree_vector_builder elements; + elements.new_unary_operation (type, arg0, true); + unsigned int i, count = elements.encoded_nelts (); + for (i = 0; i < count; ++i) + { + elem = VECTOR_CST_ELT (arg0, i); + elem = const_unop (BIT_NOT_EXPR, TREE_TYPE (type), elem); + if (elem == NULL_TREE) + break; + elements.quick_push (elem); + } + if (i == count) + return elements.build (); + } + break; + + case TRUTH_NOT_EXPR: + if (TREE_CODE (arg0) == INTEGER_CST) + return constant_boolean_node (integer_zerop (arg0), type); + break; + + case REALPART_EXPR: + if (TREE_CODE (arg0) == COMPLEX_CST) + return fold_convert (type, TREE_REALPART (arg0)); + break; + + case IMAGPART_EXPR: + if (TREE_CODE (arg0) == COMPLEX_CST) + return fold_convert (type, TREE_IMAGPART (arg0)); + break; + + case VEC_UNPACK_LO_EXPR: + case VEC_UNPACK_HI_EXPR: + case VEC_UNPACK_FLOAT_LO_EXPR: + case VEC_UNPACK_FLOAT_HI_EXPR: + case VEC_UNPACK_FIX_TRUNC_LO_EXPR: + case VEC_UNPACK_FIX_TRUNC_HI_EXPR: + { + unsigned HOST_WIDE_INT out_nelts, in_nelts, i; + enum tree_code subcode; + + if (TREE_CODE (arg0) != VECTOR_CST) + return NULL_TREE; + + if (!VECTOR_CST_NELTS (arg0).is_constant (&in_nelts)) + return NULL_TREE; + out_nelts = in_nelts / 2; + gcc_assert (known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); + + unsigned int offset = 0; + if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR + || code == VEC_UNPACK_FLOAT_LO_EXPR + || code == VEC_UNPACK_FIX_TRUNC_LO_EXPR)) + offset = out_nelts; + + if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR) + subcode = NOP_EXPR; + else if (code == VEC_UNPACK_FLOAT_LO_EXPR + || code == VEC_UNPACK_FLOAT_HI_EXPR) + subcode = FLOAT_EXPR; + else + subcode = FIX_TRUNC_EXPR; + + tree_vector_builder elts (type, out_nelts, 1); + for (i = 0; i < out_nelts; i++) + { + tree elt = fold_convert_const (subcode, TREE_TYPE (type), + VECTOR_CST_ELT (arg0, i + offset)); + if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); + } + + case VEC_DUPLICATE_EXPR: + if (CONSTANT_CLASS_P (arg0)) + return build_vector_from_val (type, arg0); + return NULL_TREE; + + default: + break; + } + + return NULL_TREE; +} + +/* Create a sizetype INT_CST node with NUMBER sign extended. KIND + indicates which particular sizetype to create. */ + +tree +size_int_kind (poly_int64 number, enum size_type_kind kind) +{ + return build_int_cst (sizetype_tab[(int) kind], number); +} + +/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE + is a tree code. The type of the result is taken from the operands. + Both must be equivalent integer types, ala int_binop_types_match_p. + If the operands are constant, so is the result. */ + +tree +size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1) +{ + tree type = TREE_TYPE (arg0); + + if (arg0 == error_mark_node || arg1 == error_mark_node) + return error_mark_node; + + gcc_assert (int_binop_types_match_p (code, TREE_TYPE (arg0), + TREE_TYPE (arg1))); + + /* Handle the special case of two poly_int constants faster. */ + if (poly_int_tree_p (arg0) && poly_int_tree_p (arg1)) + { + /* And some specific cases even faster than that. */ + if (code == PLUS_EXPR) + { + if (integer_zerop (arg0) + && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0))) + return arg1; + if (integer_zerop (arg1) + && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1))) + return arg0; + } + else if (code == MINUS_EXPR) + { + if (integer_zerop (arg1) + && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1))) + return arg0; + } + else if (code == MULT_EXPR) + { + if (integer_onep (arg0) + && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0))) + return arg1; + } + + /* Handle general case of two integer constants. For sizetype + constant calculations we always want to know about overflow, + even in the unsigned case. */ + tree res = int_const_binop (code, arg0, arg1, -1); + if (res != NULL_TREE) + return res; + } + + return fold_build2_loc (loc, code, type, arg0, arg1); +} + +/* Given two values, either both of sizetype or both of bitsizetype, + compute the difference between the two values. Return the value + in signed type corresponding to the type of the operands. */ + +tree +size_diffop_loc (location_t loc, tree arg0, tree arg1) +{ + tree type = TREE_TYPE (arg0); + tree ctype; + + gcc_assert (int_binop_types_match_p (MINUS_EXPR, TREE_TYPE (arg0), + TREE_TYPE (arg1))); + + /* If the type is already signed, just do the simple thing. */ + if (!TYPE_UNSIGNED (type)) + return size_binop_loc (loc, MINUS_EXPR, arg0, arg1); + + if (type == sizetype) + ctype = ssizetype; + else if (type == bitsizetype) + ctype = sbitsizetype; + else + ctype = signed_type_for (type); + + /* If either operand is not a constant, do the conversions to the signed + type and subtract. The hardware will do the right thing with any + overflow in the subtraction. */ + if (TREE_CODE (arg0) != INTEGER_CST || TREE_CODE (arg1) != INTEGER_CST) + return size_binop_loc (loc, MINUS_EXPR, + fold_convert_loc (loc, ctype, arg0), + fold_convert_loc (loc, ctype, arg1)); + + /* If ARG0 is larger than ARG1, subtract and return the result in CTYPE. + Otherwise, subtract the other way, convert to CTYPE (we know that can't + overflow) and negate (which can't either). Special-case a result + of zero while we're here. */ + if (tree_int_cst_equal (arg0, arg1)) + return build_int_cst (ctype, 0); + else if (tree_int_cst_lt (arg1, arg0)) + return fold_convert_loc (loc, ctype, + size_binop_loc (loc, MINUS_EXPR, arg0, arg1)); + else + return size_binop_loc (loc, MINUS_EXPR, build_int_cst (ctype, 0), + fold_convert_loc (loc, ctype, + size_binop_loc (loc, + MINUS_EXPR, + arg1, arg0))); +} + +/* A subroutine of fold_convert_const handling conversions of an + INTEGER_CST to another integer type. */ + +static tree +fold_convert_const_int_from_int (tree type, const_tree arg1) +{ + /* Given an integer constant, make new constant with new type, + appropriately sign-extended or truncated. Use widest_int + so that any extension is done according ARG1's type. */ + return force_fit_type (type, wi::to_widest (arg1), + !POINTER_TYPE_P (TREE_TYPE (arg1)), + TREE_OVERFLOW (arg1)); +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to an integer type. */ + +static tree +fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg1) +{ + bool overflow = false; + tree t; + + /* The following code implements the floating point to integer + conversion rules required by the Java Language Specification, + that IEEE NaNs are mapped to zero and values that overflow + the target precision saturate, i.e. values greater than + INT_MAX are mapped to INT_MAX, and values less than INT_MIN + are mapped to INT_MIN. These semantics are allowed by the + C and C++ standards that simply state that the behavior of + FP-to-integer conversion is unspecified upon overflow. */ + + wide_int val; + REAL_VALUE_TYPE r; + REAL_VALUE_TYPE x = TREE_REAL_CST (arg1); + + switch (code) + { + case FIX_TRUNC_EXPR: + real_trunc (&r, VOIDmode, &x); + break; + + default: + gcc_unreachable (); + } + + /* If R is NaN, return zero and show we have an overflow. */ + if (REAL_VALUE_ISNAN (r)) + { + overflow = true; + val = wi::zero (TYPE_PRECISION (type)); + } + + /* See if R is less than the lower bound or greater than the + upper bound. */ + + if (! overflow) + { + tree lt = TYPE_MIN_VALUE (type); + REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt); + if (real_less (&r, &l)) + { + overflow = true; + val = wi::to_wide (lt); + } + } + + if (! overflow) + { + tree ut = TYPE_MAX_VALUE (type); + if (ut) + { + REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut); + if (real_less (&u, &r)) + { + overflow = true; + val = wi::to_wide (ut); + } + } + } + + if (! overflow) + val = real_to_integer (&r, &overflow, TYPE_PRECISION (type)); + + t = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (arg1)); + return t; +} + +/* A subroutine of fold_convert_const handling conversions of a + FIXED_CST to an integer type. */ + +static tree +fold_convert_const_int_from_fixed (tree type, const_tree arg1) +{ + tree t; + double_int temp, temp_trunc; + scalar_mode mode; + + /* Right shift FIXED_CST to temp by fbit. */ + temp = TREE_FIXED_CST (arg1).data; + mode = TREE_FIXED_CST (arg1).mode; + if (GET_MODE_FBIT (mode) < HOST_BITS_PER_DOUBLE_INT) + { + temp = temp.rshift (GET_MODE_FBIT (mode), + HOST_BITS_PER_DOUBLE_INT, + SIGNED_FIXED_POINT_MODE_P (mode)); + + /* Left shift temp to temp_trunc by fbit. */ + temp_trunc = temp.lshift (GET_MODE_FBIT (mode), + HOST_BITS_PER_DOUBLE_INT, + SIGNED_FIXED_POINT_MODE_P (mode)); + } + else + { + temp = double_int_zero; + temp_trunc = double_int_zero; + } + + /* If FIXED_CST is negative, we need to round the value toward 0. + By checking if the fractional bits are not zero to add 1 to temp. */ + if (SIGNED_FIXED_POINT_MODE_P (mode) + && temp_trunc.is_negative () + && TREE_FIXED_CST (arg1).data != temp_trunc) + temp += double_int_one; + + /* Given a fixed-point constant, make new constant with new type, + appropriately sign-extended or truncated. */ + t = force_fit_type (type, temp, -1, + (temp.is_negative () + && (TYPE_UNSIGNED (type) + < TYPE_UNSIGNED (TREE_TYPE (arg1)))) + | TREE_OVERFLOW (arg1)); + + return t; +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to another floating point type. */ + +static tree +fold_convert_const_real_from_real (tree type, const_tree arg1) +{ + REAL_VALUE_TYPE value; + tree t; + + /* Don't perform the operation if flag_signaling_nans is on + and the operand is a signaling NaN. */ + if (HONOR_SNANS (arg1) + && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1))) + return NULL_TREE; + + /* With flag_rounding_math we should respect the current rounding mode + unless the conversion is exact. */ + if (HONOR_SIGN_DEPENDENT_ROUNDING (arg1) + && !exact_real_truncate (TYPE_MODE (type), &TREE_REAL_CST (arg1))) + return NULL_TREE; + + real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1)); + t = build_real (type, value); + + /* If converting an infinity or NAN to a representation that doesn't + have one, set the overflow bit so that we can produce some kind of + error message at the appropriate point if necessary. It's not the + most user-friendly message, but it's better than nothing. */ + if (REAL_VALUE_ISINF (TREE_REAL_CST (arg1)) + && !MODE_HAS_INFINITIES (TYPE_MODE (type))) + TREE_OVERFLOW (t) = 1; + else if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)) + && !MODE_HAS_NANS (TYPE_MODE (type))) + TREE_OVERFLOW (t) = 1; + /* Regular overflow, conversion produced an infinity in a mode that + can't represent them. */ + else if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) + && REAL_VALUE_ISINF (value) + && !REAL_VALUE_ISINF (TREE_REAL_CST (arg1))) + TREE_OVERFLOW (t) = 1; + else + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); + return t; +} + +/* A subroutine of fold_convert_const handling conversions a FIXED_CST + to a floating point type. */ + +static tree +fold_convert_const_real_from_fixed (tree type, const_tree arg1) +{ + REAL_VALUE_TYPE value; + tree t; + + real_convert_from_fixed (&value, SCALAR_FLOAT_TYPE_MODE (type), + &TREE_FIXED_CST (arg1)); + t = build_real (type, value); + + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); + return t; +} + +/* A subroutine of fold_convert_const handling conversions a FIXED_CST + to another fixed-point type. */ + +static tree +fold_convert_const_fixed_from_fixed (tree type, const_tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + bool overflow_p; + + overflow_p = fixed_convert (&value, SCALAR_TYPE_MODE (type), + &TREE_FIXED_CST (arg1), TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + TREE_OVERFLOW (t) = 1; + return t; +} + +/* A subroutine of fold_convert_const handling conversions an INTEGER_CST + to a fixed-point type. */ + +static tree +fold_convert_const_fixed_from_int (tree type, const_tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + bool overflow_p; + double_int di; + + gcc_assert (TREE_INT_CST_NUNITS (arg1) <= 2); + + di.low = TREE_INT_CST_ELT (arg1, 0); + if (TREE_INT_CST_NUNITS (arg1) == 1) + di.high = (HOST_WIDE_INT) di.low < 0 ? HOST_WIDE_INT_M1 : 0; + else + di.high = TREE_INT_CST_ELT (arg1, 1); + + overflow_p = fixed_convert_from_int (&value, SCALAR_TYPE_MODE (type), di, + TYPE_UNSIGNED (TREE_TYPE (arg1)), + TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + TREE_OVERFLOW (t) = 1; + return t; +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to a fixed-point type. */ + +static tree +fold_convert_const_fixed_from_real (tree type, const_tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + bool overflow_p; + + overflow_p = fixed_convert_from_real (&value, SCALAR_TYPE_MODE (type), + &TREE_REAL_CST (arg1), + TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + TREE_OVERFLOW (t) = 1; + return t; +} + +/* Attempt to fold type conversion operation CODE of expression ARG1 to + type TYPE. If no simplification can be done return NULL_TREE. */ + +static tree +fold_convert_const (enum tree_code code, tree type, tree arg1) +{ + tree arg_type = TREE_TYPE (arg1); + if (arg_type == type) + return arg1; + + /* We can't widen types, since the runtime value could overflow the + original type before being extended to the new type. */ + if (POLY_INT_CST_P (arg1) + && (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)) + && TYPE_PRECISION (type) <= TYPE_PRECISION (arg_type)) + return build_poly_int_cst (type, + poly_wide_int::from (poly_int_cst_value (arg1), + TYPE_PRECISION (type), + TYPE_SIGN (arg_type))); + + if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE) + { + if (TREE_CODE (arg1) == INTEGER_CST) + return fold_convert_const_int_from_int (type, arg1); + else if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_int_from_real (code, type, arg1); + else if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_int_from_fixed (type, arg1); + } + else if (TREE_CODE (type) == REAL_TYPE) + { + if (TREE_CODE (arg1) == INTEGER_CST) + { + tree res = build_real_from_int_cst (type, arg1); + /* Avoid the folding if flag_rounding_math is on and the + conversion is not exact. */ + if (HONOR_SIGN_DEPENDENT_ROUNDING (type)) + { + bool fail = false; + wide_int w = real_to_integer (&TREE_REAL_CST (res), &fail, + TYPE_PRECISION (TREE_TYPE (arg1))); + if (fail || wi::ne_p (w, wi::to_wide (arg1))) + return NULL_TREE; + } + return res; + } + else if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_real_from_real (type, arg1); + else if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_real_from_fixed (type, arg1); + } + else if (TREE_CODE (type) == FIXED_POINT_TYPE) + { + if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_fixed_from_fixed (type, arg1); + else if (TREE_CODE (arg1) == INTEGER_CST) + return fold_convert_const_fixed_from_int (type, arg1); + else if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_fixed_from_real (type, arg1); + } + else if (TREE_CODE (type) == VECTOR_TYPE) + { + if (TREE_CODE (arg1) == VECTOR_CST + && known_eq (TYPE_VECTOR_SUBPARTS (type), VECTOR_CST_NELTS (arg1))) + { + tree elttype = TREE_TYPE (type); + tree arg1_elttype = TREE_TYPE (TREE_TYPE (arg1)); + /* We can't handle steps directly when extending, since the + values need to wrap at the original precision first. */ + bool step_ok_p + = (INTEGRAL_TYPE_P (elttype) + && INTEGRAL_TYPE_P (arg1_elttype) + && TYPE_PRECISION (elttype) <= TYPE_PRECISION (arg1_elttype)); + tree_vector_builder v; + if (!v.new_unary_operation (type, arg1, step_ok_p)) + return NULL_TREE; + unsigned int len = v.encoded_nelts (); + for (unsigned int i = 0; i < len; ++i) + { + tree elt = VECTOR_CST_ELT (arg1, i); + tree cvt = fold_convert_const (code, elttype, elt); + if (cvt == NULL_TREE) + return NULL_TREE; + v.quick_push (cvt); + } + return v.build (); + } + } + return NULL_TREE; +} + +/* Construct a vector of zero elements of vector type TYPE. */ + +static tree +build_zero_vector (tree type) +{ + tree t; + + t = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node); + return build_vector_from_val (type, t); +} + +/* Returns true, if ARG is convertible to TYPE using a NOP_EXPR. */ + +bool +fold_convertible_p (const_tree type, const_tree arg) +{ + tree orig = TREE_TYPE (arg); + + if (type == orig) + return true; + + if (TREE_CODE (arg) == ERROR_MARK + || TREE_CODE (type) == ERROR_MARK + || TREE_CODE (orig) == ERROR_MARK) + return false; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)) + return true; + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + case OFFSET_TYPE: + return (INTEGRAL_TYPE_P (orig) + || (POINTER_TYPE_P (orig) + && TYPE_PRECISION (type) <= TYPE_PRECISION (orig)) + || TREE_CODE (orig) == OFFSET_TYPE); + + case REAL_TYPE: + case FIXED_POINT_TYPE: + case VOID_TYPE: + return TREE_CODE (type) == TREE_CODE (orig); + + case VECTOR_TYPE: + return (VECTOR_TYPE_P (orig) + && known_eq (TYPE_VECTOR_SUBPARTS (type), + TYPE_VECTOR_SUBPARTS (orig)) + && fold_convertible_p (TREE_TYPE (type), TREE_TYPE (orig))); + + default: + return false; + } +} + +/* Convert expression ARG to type TYPE. Used by the middle-end for + simple conversions in preference to calling the front-end's convert. */ + +tree +fold_convert_loc (location_t loc, tree type, tree arg) +{ + tree orig = TREE_TYPE (arg); + tree tem; + + if (type == orig) + return arg; + + if (TREE_CODE (arg) == ERROR_MARK + || TREE_CODE (type) == ERROR_MARK + || TREE_CODE (orig) == ERROR_MARK) + return error_mark_node; + + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + /* Handle conversions between pointers to different address spaces. */ + if (POINTER_TYPE_P (orig) + && (TYPE_ADDR_SPACE (TREE_TYPE (type)) + != TYPE_ADDR_SPACE (TREE_TYPE (orig)))) + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, arg); + /* fall through */ + + case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: + case OFFSET_TYPE: + if (TREE_CODE (arg) == INTEGER_CST) + { + tem = fold_convert_const (NOP_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) + || TREE_CODE (orig) == OFFSET_TYPE) + return fold_build1_loc (loc, NOP_EXPR, type, arg); + if (TREE_CODE (orig) == COMPLEX_TYPE) + return fold_convert_loc (loc, type, + fold_build1_loc (loc, REALPART_EXPR, + TREE_TYPE (orig), arg)); + gcc_assert (TREE_CODE (orig) == VECTOR_TYPE + && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); + return fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, arg); + + case REAL_TYPE: + if (TREE_CODE (arg) == INTEGER_CST) + { + tem = fold_convert_const (FLOAT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + else if (TREE_CODE (arg) == REAL_CST) + { + tem = fold_convert_const (NOP_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + else if (TREE_CODE (arg) == FIXED_CST) + { + tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + + switch (TREE_CODE (orig)) + { + case INTEGER_TYPE: + case BOOLEAN_TYPE: case ENUMERAL_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + return fold_build1_loc (loc, FLOAT_EXPR, type, arg); + + case REAL_TYPE: + return fold_build1_loc (loc, NOP_EXPR, type, arg); + + case FIXED_POINT_TYPE: + return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg); + + case COMPLEX_TYPE: + tem = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); + return fold_convert_loc (loc, type, tem); + + default: + gcc_unreachable (); + } + + case FIXED_POINT_TYPE: + if (TREE_CODE (arg) == FIXED_CST || TREE_CODE (arg) == INTEGER_CST + || TREE_CODE (arg) == REAL_CST) + { + tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); + if (tem != NULL_TREE) + goto fold_convert_exit; + } + + switch (TREE_CODE (orig)) + { + case FIXED_POINT_TYPE: + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case REAL_TYPE: + return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg); + + case COMPLEX_TYPE: + tem = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); + return fold_convert_loc (loc, type, tem); + + default: + gcc_unreachable (); + } + + case COMPLEX_TYPE: + switch (TREE_CODE (orig)) + { + case INTEGER_TYPE: + case BOOLEAN_TYPE: case ENUMERAL_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + return fold_build2_loc (loc, COMPLEX_EXPR, type, + fold_convert_loc (loc, TREE_TYPE (type), arg), + fold_convert_loc (loc, TREE_TYPE (type), + integer_zero_node)); + case COMPLEX_TYPE: + { + tree rpart, ipart; + + if (TREE_CODE (arg) == COMPLEX_EXPR) + { + rpart = fold_convert_loc (loc, TREE_TYPE (type), + TREE_OPERAND (arg, 0)); + ipart = fold_convert_loc (loc, TREE_TYPE (type), + TREE_OPERAND (arg, 1)); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart, ipart); + } + + arg = save_expr (arg); + rpart = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); + ipart = fold_build1_loc (loc, IMAGPART_EXPR, TREE_TYPE (orig), arg); + rpart = fold_convert_loc (loc, TREE_TYPE (type), rpart); + ipart = fold_convert_loc (loc, TREE_TYPE (type), ipart); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart, ipart); + } + + default: + gcc_unreachable (); + } + + case VECTOR_TYPE: + if (integer_zerop (arg)) + return build_zero_vector (type); + gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); + gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) + || TREE_CODE (orig) == VECTOR_TYPE); + return fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, arg); + + case VOID_TYPE: + tem = fold_ignored_result (arg); + return fold_build1_loc (loc, NOP_EXPR, type, tem); + + default: + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)) + return fold_build1_loc (loc, NOP_EXPR, type, arg); + gcc_unreachable (); + } + fold_convert_exit: + protected_set_expr_location_unshare (tem, loc); + return tem; +} + +/* Return false if expr can be assumed not to be an lvalue, true + otherwise. */ + +static bool +maybe_lvalue_p (const_tree x) +{ + /* We only need to wrap lvalue tree codes. */ + switch (TREE_CODE (x)) + { + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case LABEL_DECL: + case FUNCTION_DECL: + case SSA_NAME: + + case COMPONENT_REF: + case MEM_REF: + case INDIRECT_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + case BIT_FIELD_REF: + case OBJ_TYPE_REF: + + case REALPART_EXPR: + case IMAGPART_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case SAVE_EXPR: + case TRY_CATCH_EXPR: + case WITH_CLEANUP_EXPR: + case COMPOUND_EXPR: + case MODIFY_EXPR: + case TARGET_EXPR: + case COND_EXPR: + case BIND_EXPR: + case VIEW_CONVERT_EXPR: + break; + + default: + /* Assume the worst for front-end tree codes. */ + if ((int)TREE_CODE (x) >= NUM_TREE_CODES) + break; + return false; + } + + return true; +} + +/* Return an expr equal to X but certainly not valid as an lvalue. */ + +tree +non_lvalue_loc (location_t loc, tree x) +{ + /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to + us. */ + if (in_gimple_form) + return x; + + if (! maybe_lvalue_p (x)) + return x; + return build1_loc (loc, NON_LVALUE_EXPR, TREE_TYPE (x), x); +} + +/* Given a tree comparison code, return the code that is the logical inverse. + It is generally not safe to do this for floating-point comparisons, except + for EQ_EXPR, NE_EXPR, ORDERED_EXPR and UNORDERED_EXPR, so we return + ERROR_MARK in this case. */ + +enum tree_code +invert_tree_comparison (enum tree_code code, bool honor_nans) +{ + if (honor_nans && flag_trapping_math && code != EQ_EXPR && code != NE_EXPR + && code != ORDERED_EXPR && code != UNORDERED_EXPR) + return ERROR_MARK; + + switch (code) + { + case EQ_EXPR: + return NE_EXPR; + case NE_EXPR: + return EQ_EXPR; + case GT_EXPR: + return honor_nans ? UNLE_EXPR : LE_EXPR; + case GE_EXPR: + return honor_nans ? UNLT_EXPR : LT_EXPR; + case LT_EXPR: + return honor_nans ? UNGE_EXPR : GE_EXPR; + case LE_EXPR: + return honor_nans ? UNGT_EXPR : GT_EXPR; + case LTGT_EXPR: + return UNEQ_EXPR; + case UNEQ_EXPR: + return LTGT_EXPR; + case UNGT_EXPR: + return LE_EXPR; + case UNGE_EXPR: + return LT_EXPR; + case UNLT_EXPR: + return GE_EXPR; + case UNLE_EXPR: + return GT_EXPR; + case ORDERED_EXPR: + return UNORDERED_EXPR; + case UNORDERED_EXPR: + return ORDERED_EXPR; + default: + gcc_unreachable (); + } +} + +/* Similar, but return the comparison that results if the operands are + swapped. This is safe for floating-point. */ + +enum tree_code +swap_tree_comparison (enum tree_code code) +{ + switch (code) + { + case EQ_EXPR: + case NE_EXPR: + case ORDERED_EXPR: + case UNORDERED_EXPR: + case LTGT_EXPR: + case UNEQ_EXPR: + return code; + case GT_EXPR: + return LT_EXPR; + case GE_EXPR: + return LE_EXPR; + case LT_EXPR: + return GT_EXPR; + case LE_EXPR: + return GE_EXPR; + case UNGT_EXPR: + return UNLT_EXPR; + case UNGE_EXPR: + return UNLE_EXPR; + case UNLT_EXPR: + return UNGT_EXPR; + case UNLE_EXPR: + return UNGE_EXPR; + default: + gcc_unreachable (); + } +} + + +/* Convert a comparison tree code from an enum tree_code representation + into a compcode bit-based encoding. This function is the inverse of + compcode_to_comparison. */ + +static enum comparison_code +comparison_to_compcode (enum tree_code code) +{ + switch (code) + { + case LT_EXPR: + return COMPCODE_LT; + case EQ_EXPR: + return COMPCODE_EQ; + case LE_EXPR: + return COMPCODE_LE; + case GT_EXPR: + return COMPCODE_GT; + case NE_EXPR: + return COMPCODE_NE; + case GE_EXPR: + return COMPCODE_GE; + case ORDERED_EXPR: + return COMPCODE_ORD; + case UNORDERED_EXPR: + return COMPCODE_UNORD; + case UNLT_EXPR: + return COMPCODE_UNLT; + case UNEQ_EXPR: + return COMPCODE_UNEQ; + case UNLE_EXPR: + return COMPCODE_UNLE; + case UNGT_EXPR: + return COMPCODE_UNGT; + case LTGT_EXPR: + return COMPCODE_LTGT; + case UNGE_EXPR: + return COMPCODE_UNGE; + default: + gcc_unreachable (); + } +} + +/* Convert a compcode bit-based encoding of a comparison operator back + to GCC's enum tree_code representation. This function is the + inverse of comparison_to_compcode. */ + +static enum tree_code +compcode_to_comparison (enum comparison_code code) +{ + switch (code) + { + case COMPCODE_LT: + return LT_EXPR; + case COMPCODE_EQ: + return EQ_EXPR; + case COMPCODE_LE: + return LE_EXPR; + case COMPCODE_GT: + return GT_EXPR; + case COMPCODE_NE: + return NE_EXPR; + case COMPCODE_GE: + return GE_EXPR; + case COMPCODE_ORD: + return ORDERED_EXPR; + case COMPCODE_UNORD: + return UNORDERED_EXPR; + case COMPCODE_UNLT: + return UNLT_EXPR; + case COMPCODE_UNEQ: + return UNEQ_EXPR; + case COMPCODE_UNLE: + return UNLE_EXPR; + case COMPCODE_UNGT: + return UNGT_EXPR; + case COMPCODE_LTGT: + return LTGT_EXPR; + case COMPCODE_UNGE: + return UNGE_EXPR; + default: + gcc_unreachable (); + } +} + +/* Return true if COND1 tests the opposite condition of COND2. */ + +bool +inverse_conditions_p (const_tree cond1, const_tree cond2) +{ + return (COMPARISON_CLASS_P (cond1) + && COMPARISON_CLASS_P (cond2) + && (invert_tree_comparison + (TREE_CODE (cond1), + HONOR_NANS (TREE_OPERAND (cond1, 0))) == TREE_CODE (cond2)) + && operand_equal_p (TREE_OPERAND (cond1, 0), + TREE_OPERAND (cond2, 0), 0) + && operand_equal_p (TREE_OPERAND (cond1, 1), + TREE_OPERAND (cond2, 1), 0)); +} + +/* Return a tree for the comparison which is the combination of + doing the AND or OR (depending on CODE) of the two operations LCODE + and RCODE on the identical operands LL_ARG and LR_ARG. Take into account + the possibility of trapping if the mode has NaNs, and return NULL_TREE + if this makes the transformation invalid. */ + +tree +combine_comparisons (location_t loc, + enum tree_code code, enum tree_code lcode, + enum tree_code rcode, tree truth_type, + tree ll_arg, tree lr_arg) +{ + bool honor_nans = HONOR_NANS (ll_arg); + enum comparison_code lcompcode = comparison_to_compcode (lcode); + enum comparison_code rcompcode = comparison_to_compcode (rcode); + int compcode; + + switch (code) + { + case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: + compcode = lcompcode & rcompcode; + break; + + case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: + compcode = lcompcode | rcompcode; + break; + + default: + return NULL_TREE; + } + + if (!honor_nans) + { + /* Eliminate unordered comparisons, as well as LTGT and ORD + which are not used unless the mode has NaNs. */ + compcode &= ~COMPCODE_UNORD; + if (compcode == COMPCODE_LTGT) + compcode = COMPCODE_NE; + else if (compcode == COMPCODE_ORD) + compcode = COMPCODE_TRUE; + } + else if (flag_trapping_math) + { + /* Check that the original operation and the optimized ones will trap + under the same condition. */ + bool ltrap = (lcompcode & COMPCODE_UNORD) == 0 + && (lcompcode != COMPCODE_EQ) + && (lcompcode != COMPCODE_ORD); + bool rtrap = (rcompcode & COMPCODE_UNORD) == 0 + && (rcompcode != COMPCODE_EQ) + && (rcompcode != COMPCODE_ORD); + bool trap = (compcode & COMPCODE_UNORD) == 0 + && (compcode != COMPCODE_EQ) + && (compcode != COMPCODE_ORD); + + /* In a short-circuited boolean expression the LHS might be + such that the RHS, if evaluated, will never trap. For + example, in ORD (x, y) && (x < y), we evaluate the RHS only + if neither x nor y is NaN. (This is a mixed blessing: for + example, the expression above will never trap, hence + optimizing it to x < y would be invalid). */ + if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD)) + || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD))) + rtrap = false; + + /* If the comparison was short-circuited, and only the RHS + trapped, we may now generate a spurious trap. */ + if (rtrap && !ltrap + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) + return NULL_TREE; + + /* If we changed the conditions that cause a trap, we lose. */ + if ((ltrap || rtrap) != trap) + return NULL_TREE; + } + + if (compcode == COMPCODE_TRUE) + return constant_boolean_node (true, truth_type); + else if (compcode == COMPCODE_FALSE) + return constant_boolean_node (false, truth_type); + else + { + enum tree_code tcode; + + tcode = compcode_to_comparison ((enum comparison_code) compcode); + return fold_build2_loc (loc, tcode, truth_type, ll_arg, lr_arg); + } +} + +/* Return nonzero if two operands (typically of the same tree node) + are necessarily equal. FLAGS modifies behavior as follows: + + If OEP_ONLY_CONST is set, only return nonzero for constants. + This function tests whether the operands are indistinguishable; + it does not test whether they are equal using C's == operation. + The distinction is important for IEEE floating point, because + (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and + (2) two NaNs may be indistinguishable, but NaN!=NaN. + + If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself + even though it may hold multiple values during a function. + This is because a GCC tree node guarantees that nothing else is + executed between the evaluation of its "operands" (which may often + be evaluated in arbitrary order). Hence if the operands themselves + don't side-effect, the VAR_DECLs, PARM_DECLs etc... must hold the + same value in each operand/subexpression. Hence leaving OEP_ONLY_CONST + unset means assuming isochronic (or instantaneous) tree equivalence. + Unless comparing arbitrary expression trees, such as from different + statements, this flag can usually be left unset. + + If OEP_PURE_SAME is set, then pure functions with identical arguments + are considered the same. It is used when the caller has other ways + to ensure that global memory is unchanged in between. + + If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects, + not values of expressions. + + If OEP_LEXICOGRAPHIC is set, then also handle expressions with side-effects + such as MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs. + + If OEP_BITWISE is set, then require the values to be bitwise identical + rather than simply numerically equal. Do not take advantage of things + like math-related flags or undefined behavior; only return true for + values that are provably bitwise identical in all circumstances. + + Unless OEP_MATCH_SIDE_EFFECTS is set, the function returns false on + any operand with side effect. This is unnecesarily conservative in the + case we know that arg0 and arg1 are in disjoint code paths (such as in + ?: operator). In addition OEP_MATCH_SIDE_EFFECTS is used when comparing + addresses with TREE_CONSTANT flag set so we know that &var == &var + even if var is volatile. */ + +bool +operand_compare::operand_equal_p (const_tree arg0, const_tree arg1, + unsigned int flags) +{ + bool r; + if (verify_hash_value (arg0, arg1, flags, &r)) + return r; + + STRIP_ANY_LOCATION_WRAPPER (arg0); + STRIP_ANY_LOCATION_WRAPPER (arg1); + + /* If either is ERROR_MARK, they aren't equal. */ + if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK + || TREE_TYPE (arg0) == error_mark_node + || TREE_TYPE (arg1) == error_mark_node) + return false; + + /* Similar, if either does not have a type (like a template id), + they aren't equal. */ + if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1)) + return false; + + /* Bitwise identity makes no sense if the values have different layouts. */ + if ((flags & OEP_BITWISE) + && !tree_nop_conversion_p (TREE_TYPE (arg0), TREE_TYPE (arg1))) + return false; + + /* We cannot consider pointers to different address space equal. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) + && POINTER_TYPE_P (TREE_TYPE (arg1)) + && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0))) + != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1))))) + return false; + + /* Check equality of integer constants before bailing out due to + precision differences. */ + if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + { + /* Address of INTEGER_CST is not defined; check that we did not forget + to drop the OEP_ADDRESS_OF flags. */ + gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); + return tree_int_cst_equal (arg0, arg1); + } + + if (!(flags & OEP_ADDRESS_OF)) + { + /* If both types don't have the same signedness, then we can't consider + them equal. We must check this before the STRIP_NOPS calls + because they may change the signedness of the arguments. As pointers + strictly don't have a signedness, require either two pointers or + two non-pointers as well. */ + if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)) + || POINTER_TYPE_P (TREE_TYPE (arg0)) + != POINTER_TYPE_P (TREE_TYPE (arg1))) + return false; + + /* If both types don't have the same precision, then it is not safe + to strip NOPs. */ + if (element_precision (TREE_TYPE (arg0)) + != element_precision (TREE_TYPE (arg1))) + return false; + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + } +#if 0 + /* FIXME: Fortran FE currently produce ADDR_EXPR of NOP_EXPR. Enable the + sanity check once the issue is solved. */ + else + /* Addresses of conversions and SSA_NAMEs (and many other things) + are not defined. Check that we did not forget to drop the + OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF flags. */ + gcc_checking_assert (!CONVERT_EXPR_P (arg0) && !CONVERT_EXPR_P (arg1) + && TREE_CODE (arg0) != SSA_NAME); +#endif + + /* In case both args are comparisons but with different comparison + code, try to swap the comparison operands of one arg to produce + a match and compare that variant. */ + if (TREE_CODE (arg0) != TREE_CODE (arg1) + && COMPARISON_CLASS_P (arg0) + && COMPARISON_CLASS_P (arg1)) + { + enum tree_code swap_code = swap_tree_comparison (TREE_CODE (arg1)); + + if (TREE_CODE (arg0) == swap_code) + return operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags); + } + + if (TREE_CODE (arg0) != TREE_CODE (arg1)) + { + /* NOP_EXPR and CONVERT_EXPR are considered equal. */ + if (CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1)) + ; + else if (flags & OEP_ADDRESS_OF) + { + /* If we are interested in comparing addresses ignore + MEM_REF wrappings of the base that can appear just for + TBAA reasons. */ + if (TREE_CODE (arg0) == MEM_REF + && DECL_P (arg1) + && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR + && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1 + && integer_zerop (TREE_OPERAND (arg0, 1))) + return true; + else if (TREE_CODE (arg1) == MEM_REF + && DECL_P (arg0) + && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR + && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0 + && integer_zerop (TREE_OPERAND (arg1, 1))) + return true; + return false; + } + else + return false; + } + + /* When not checking adddresses, this is needed for conversions and for + COMPONENT_REF. Might as well play it safe and always test this. */ + if (TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK + || (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)) + && !(flags & OEP_ADDRESS_OF))) + return false; + + /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal. + We don't care about side effects in that case because the SAVE_EXPR + takes care of that for us. In all other cases, two expressions are + equal if they have no side effects. If we have two identical + expressions with side effects that should be treated the same due + to the only side effects being identical SAVE_EXPR's, that will + be detected in the recursive calls below. + If we are taking an invariant address of two identical objects + they are necessarily equal as well. */ + if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST) + && (TREE_CODE (arg0) == SAVE_EXPR + || (flags & OEP_MATCH_SIDE_EFFECTS) + || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) + return true; + + /* Next handle constant cases, those for which we can return 1 even + if ONLY_CONST is set. */ + if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)) + switch (TREE_CODE (arg0)) + { + case INTEGER_CST: + return tree_int_cst_equal (arg0, arg1); + + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (arg0), + TREE_FIXED_CST (arg1)); + + case REAL_CST: + if (real_identical (&TREE_REAL_CST (arg0), &TREE_REAL_CST (arg1))) + return true; + + if (!(flags & OEP_BITWISE) && !HONOR_SIGNED_ZEROS (arg0)) + { + /* If we do not distinguish between signed and unsigned zero, + consider them equal. */ + if (real_zerop (arg0) && real_zerop (arg1)) + return true; + } + return false; + + case VECTOR_CST: + { + if (VECTOR_CST_LOG2_NPATTERNS (arg0) + != VECTOR_CST_LOG2_NPATTERNS (arg1)) + return false; + + if (VECTOR_CST_NELTS_PER_PATTERN (arg0) + != VECTOR_CST_NELTS_PER_PATTERN (arg1)) + return false; + + unsigned int count = vector_cst_encoded_nelts (arg0); + for (unsigned int i = 0; i < count; ++i) + if (!operand_equal_p (VECTOR_CST_ENCODED_ELT (arg0, i), + VECTOR_CST_ENCODED_ELT (arg1, i), flags)) + return false; + return true; + } + + case COMPLEX_CST: + return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), + flags) + && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), + flags)); + + case STRING_CST: + return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) + && ! memcmp (TREE_STRING_POINTER (arg0), + TREE_STRING_POINTER (arg1), + TREE_STRING_LENGTH (arg0))); + + case ADDR_EXPR: + gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); + return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), + flags | OEP_ADDRESS_OF + | OEP_MATCH_SIDE_EFFECTS); + case CONSTRUCTOR: + /* In GIMPLE empty constructors are allowed in initializers of + aggregates. */ + return !CONSTRUCTOR_NELTS (arg0) && !CONSTRUCTOR_NELTS (arg1); + default: + break; + } + + /* Don't handle more cases for OEP_BITWISE, since we can't guarantee that + two instances of undefined behavior will give identical results. */ + if (flags & (OEP_ONLY_CONST | OEP_BITWISE)) + return false; + +/* Define macros to test an operand from arg0 and arg1 for equality and a + variant that allows null and views null as being different from any + non-null value. In the latter case, if either is null, the both + must be; otherwise, do the normal comparison. */ +#define OP_SAME(N) operand_equal_p (TREE_OPERAND (arg0, N), \ + TREE_OPERAND (arg1, N), flags) + +#define OP_SAME_WITH_NULL(N) \ + ((!TREE_OPERAND (arg0, N) || !TREE_OPERAND (arg1, N)) \ + ? TREE_OPERAND (arg0, N) == TREE_OPERAND (arg1, N) : OP_SAME (N)) + + switch (TREE_CODE_CLASS (TREE_CODE (arg0))) + { + case tcc_unary: + /* Two conversions are equal only if signedness and modes match. */ + switch (TREE_CODE (arg0)) + { + CASE_CONVERT: + case FIX_TRUNC_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg0)) + != TYPE_UNSIGNED (TREE_TYPE (arg1))) + return false; + break; + default: + break; + } + + return OP_SAME (0); + + + case tcc_comparison: + case tcc_binary: + if (OP_SAME (0) && OP_SAME (1)) + return true; + + /* For commutative ops, allow the other order. */ + return (commutative_tree_code (TREE_CODE (arg0)) + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags)); + + case tcc_reference: + /* If either of the pointer (or reference) expressions we are + dereferencing contain a side effect, these cannot be equal, + but their addresses can be. */ + if ((flags & OEP_MATCH_SIDE_EFFECTS) == 0 + && (TREE_SIDE_EFFECTS (arg0) + || TREE_SIDE_EFFECTS (arg1))) + return false; + + switch (TREE_CODE (arg0)) + { + case INDIRECT_REF: + if (!(flags & OEP_ADDRESS_OF)) + { + if (TYPE_ALIGN (TREE_TYPE (arg0)) + != TYPE_ALIGN (TREE_TYPE (arg1))) + return false; + /* Verify that the access types are compatible. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg0)) + != TYPE_MAIN_VARIANT (TREE_TYPE (arg1))) + return false; + } + flags &= ~OEP_ADDRESS_OF; + return OP_SAME (0); + + case IMAGPART_EXPR: + /* Require the same offset. */ + if (!operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)), + TYPE_SIZE (TREE_TYPE (arg1)), + flags & ~OEP_ADDRESS_OF)) + return false; + + /* Fallthru. */ + case REALPART_EXPR: + case VIEW_CONVERT_EXPR: + return OP_SAME (0); + + case TARGET_MEM_REF: + case MEM_REF: + if (!(flags & OEP_ADDRESS_OF)) + { + /* Require equal access sizes */ + if (TYPE_SIZE (TREE_TYPE (arg0)) != TYPE_SIZE (TREE_TYPE (arg1)) + && (!TYPE_SIZE (TREE_TYPE (arg0)) + || !TYPE_SIZE (TREE_TYPE (arg1)) + || !operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)), + TYPE_SIZE (TREE_TYPE (arg1)), + flags))) + return false; + /* Verify that access happens in similar types. */ + if (!types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))) + return false; + /* Verify that accesses are TBAA compatible. */ + if (!alias_ptr_types_compatible_p + (TREE_TYPE (TREE_OPERAND (arg0, 1)), + TREE_TYPE (TREE_OPERAND (arg1, 1))) + || (MR_DEPENDENCE_CLIQUE (arg0) + != MR_DEPENDENCE_CLIQUE (arg1)) + || (MR_DEPENDENCE_BASE (arg0) + != MR_DEPENDENCE_BASE (arg1))) + return false; + /* Verify that alignment is compatible. */ + if (TYPE_ALIGN (TREE_TYPE (arg0)) + != TYPE_ALIGN (TREE_TYPE (arg1))) + return false; + } + flags &= ~OEP_ADDRESS_OF; + return (OP_SAME (0) && OP_SAME (1) + /* TARGET_MEM_REF require equal extra operands. */ + && (TREE_CODE (arg0) != TARGET_MEM_REF + || (OP_SAME_WITH_NULL (2) + && OP_SAME_WITH_NULL (3) + && OP_SAME_WITH_NULL (4)))); + + case ARRAY_REF: + case ARRAY_RANGE_REF: + if (!OP_SAME (0)) + return false; + flags &= ~OEP_ADDRESS_OF; + /* Compare the array index by value if it is constant first as we + may have different types but same value here. */ + return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 1)) + || OP_SAME (1)) + && OP_SAME_WITH_NULL (2) + && OP_SAME_WITH_NULL (3) + /* Compare low bound and element size as with OEP_ADDRESS_OF + we have to account for the offset of the ref. */ + && (TREE_TYPE (TREE_OPERAND (arg0, 0)) + == TREE_TYPE (TREE_OPERAND (arg1, 0)) + || (operand_equal_p (array_ref_low_bound + (CONST_CAST_TREE (arg0)), + array_ref_low_bound + (CONST_CAST_TREE (arg1)), flags) + && operand_equal_p (array_ref_element_size + (CONST_CAST_TREE (arg0)), + array_ref_element_size + (CONST_CAST_TREE (arg1)), + flags)))); + + case COMPONENT_REF: + /* Handle operand 2 the same as for ARRAY_REF. Operand 0 + may be NULL when we're called to compare MEM_EXPRs. */ + if (!OP_SAME_WITH_NULL (0)) + return false; + { + bool compare_address = flags & OEP_ADDRESS_OF; + + /* Most of time we only need to compare FIELD_DECLs for equality. + However when determining address look into actual offsets. + These may match for unions and unshared record types. */ + flags &= ~OEP_ADDRESS_OF; + if (!OP_SAME (1)) + { + if (compare_address + && (flags & OEP_ADDRESS_OF_SAME_FIELD) == 0) + { + if (TREE_OPERAND (arg0, 2) + || TREE_OPERAND (arg1, 2)) + return OP_SAME_WITH_NULL (2); + tree field0 = TREE_OPERAND (arg0, 1); + tree field1 = TREE_OPERAND (arg1, 1); + + if (!operand_equal_p (DECL_FIELD_OFFSET (field0), + DECL_FIELD_OFFSET (field1), flags) + || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0), + DECL_FIELD_BIT_OFFSET (field1), + flags)) + return false; + } + else + return false; + } + } + return OP_SAME_WITH_NULL (2); + + case BIT_FIELD_REF: + if (!OP_SAME (0)) + return false; + flags &= ~OEP_ADDRESS_OF; + return OP_SAME (1) && OP_SAME (2); + + default: + return false; + } + + case tcc_expression: + switch (TREE_CODE (arg0)) + { + case ADDR_EXPR: + /* Be sure we pass right ADDRESS_OF flag. */ + gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); + return operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), + flags | OEP_ADDRESS_OF); + + case TRUTH_NOT_EXPR: + return OP_SAME (0); + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + return OP_SAME (0) && OP_SAME (1); + + case WIDEN_MULT_PLUS_EXPR: + case WIDEN_MULT_MINUS_EXPR: + if (!OP_SAME (2)) + return false; + /* The multiplcation operands are commutative. */ + /* FALLTHRU */ + + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if (OP_SAME (0) && OP_SAME (1)) + return true; + + /* Otherwise take into account this is a commutative operation. */ + return (operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags)); + + case COND_EXPR: + if (! OP_SAME (1) || ! OP_SAME_WITH_NULL (2)) + return false; + flags &= ~OEP_ADDRESS_OF; + return OP_SAME (0); + + case BIT_INSERT_EXPR: + /* BIT_INSERT_EXPR has an implict operand as the type precision + of op1. Need to check to make sure they are the same. */ + if (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 1))) + != TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 1)))) + return false; + /* FALLTHRU */ + + case VEC_COND_EXPR: + case DOT_PROD_EXPR: + return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); + + case MODIFY_EXPR: + case INIT_EXPR: + case COMPOUND_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + if (flags & OEP_LEXICOGRAPHIC) + return OP_SAME (0) && OP_SAME (1); + return false; + + case CLEANUP_POINT_EXPR: + case EXPR_STMT: + case SAVE_EXPR: + if (flags & OEP_LEXICOGRAPHIC) + return OP_SAME (0); + return false; + + case OBJ_TYPE_REF: + /* Virtual table reference. */ + if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0), + OBJ_TYPE_REF_EXPR (arg1), flags)) + return false; + flags &= ~OEP_ADDRESS_OF; + if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0)) + != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1))) + return false; + if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0), + OBJ_TYPE_REF_OBJECT (arg1), flags)) + return false; + if (virtual_method_call_p (arg0)) + { + if (!virtual_method_call_p (arg1)) + return false; + return types_same_for_odr (obj_type_ref_class (arg0), + obj_type_ref_class (arg1)); + } + return false; + + default: + return false; + } + + case tcc_vl_exp: + switch (TREE_CODE (arg0)) + { + case CALL_EXPR: + if ((CALL_EXPR_FN (arg0) == NULL_TREE) + != (CALL_EXPR_FN (arg1) == NULL_TREE)) + /* If not both CALL_EXPRs are either internal or normal function + functions, then they are not equal. */ + return false; + else if (CALL_EXPR_FN (arg0) == NULL_TREE) + { + /* If the CALL_EXPRs call different internal functions, then they + are not equal. */ + if (CALL_EXPR_IFN (arg0) != CALL_EXPR_IFN (arg1)) + return false; + } + else + { + /* If the CALL_EXPRs call different functions, then they are not + equal. */ + if (! operand_equal_p (CALL_EXPR_FN (arg0), CALL_EXPR_FN (arg1), + flags)) + return false; + } + + /* FIXME: We could skip this test for OEP_MATCH_SIDE_EFFECTS. */ + { + unsigned int cef = call_expr_flags (arg0); + if (flags & OEP_PURE_SAME) + cef &= ECF_CONST | ECF_PURE; + else + cef &= ECF_CONST; + if (!cef && !(flags & OEP_LEXICOGRAPHIC)) + return false; + } + + /* Now see if all the arguments are the same. */ + { + const_call_expr_arg_iterator iter0, iter1; + const_tree a0, a1; + for (a0 = first_const_call_expr_arg (arg0, &iter0), + a1 = first_const_call_expr_arg (arg1, &iter1); + a0 && a1; + a0 = next_const_call_expr_arg (&iter0), + a1 = next_const_call_expr_arg (&iter1)) + if (! operand_equal_p (a0, a1, flags)) + return false; + + /* If we get here and both argument lists are exhausted + then the CALL_EXPRs are equal. */ + return ! (a0 || a1); + } + default: + return false; + } + + case tcc_declaration: + /* Consider __builtin_sqrt equal to sqrt. */ + if (TREE_CODE (arg0) == FUNCTION_DECL) + return (fndecl_built_in_p (arg0) && fndecl_built_in_p (arg1) + && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) + && (DECL_UNCHECKED_FUNCTION_CODE (arg0) + == DECL_UNCHECKED_FUNCTION_CODE (arg1))); + + if (DECL_P (arg0) + && (flags & OEP_DECL_NAME) + && (flags & OEP_LEXICOGRAPHIC)) + { + /* Consider decls with the same name equal. The caller needs + to make sure they refer to the same entity (such as a function + formal parameter). */ + tree a0name = DECL_NAME (arg0); + tree a1name = DECL_NAME (arg1); + const char *a0ns = a0name ? IDENTIFIER_POINTER (a0name) : NULL; + const char *a1ns = a1name ? IDENTIFIER_POINTER (a1name) : NULL; + return a0ns && a1ns && strcmp (a0ns, a1ns) == 0; + } + return false; + + case tcc_exceptional: + if (TREE_CODE (arg0) == CONSTRUCTOR) + { + if (CONSTRUCTOR_NO_CLEARING (arg0) != CONSTRUCTOR_NO_CLEARING (arg1)) + return false; + + /* In GIMPLE constructors are used only to build vectors from + elements. Individual elements in the constructor must be + indexed in increasing order and form an initial sequence. + + We make no effort to compare constructors in generic. + (see sem_variable::equals in ipa-icf which can do so for + constants). */ + if (!VECTOR_TYPE_P (TREE_TYPE (arg0)) + || !VECTOR_TYPE_P (TREE_TYPE (arg1))) + return false; + + /* Be sure that vectors constructed have the same representation. + We only tested element precision and modes to match. + Vectors may be BLKmode and thus also check that the number of + parts match. */ + if (maybe_ne (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), + TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)))) + return false; + + vec<constructor_elt, va_gc> *v0 = CONSTRUCTOR_ELTS (arg0); + vec<constructor_elt, va_gc> *v1 = CONSTRUCTOR_ELTS (arg1); + unsigned int len = vec_safe_length (v0); + + if (len != vec_safe_length (v1)) + return false; + + for (unsigned int i = 0; i < len; i++) + { + constructor_elt *c0 = &(*v0)[i]; + constructor_elt *c1 = &(*v1)[i]; + + if (!operand_equal_p (c0->value, c1->value, flags) + /* In GIMPLE the indexes can be either NULL or matching i. + Double check this so we won't get false + positives for GENERIC. */ + || (c0->index + && (TREE_CODE (c0->index) != INTEGER_CST + || compare_tree_int (c0->index, i))) + || (c1->index + && (TREE_CODE (c1->index) != INTEGER_CST + || compare_tree_int (c1->index, i)))) + return false; + } + return true; + } + else if (TREE_CODE (arg0) == STATEMENT_LIST + && (flags & OEP_LEXICOGRAPHIC)) + { + /* Compare the STATEMENT_LISTs. */ + tree_stmt_iterator tsi1, tsi2; + tree body1 = CONST_CAST_TREE (arg0); + tree body2 = CONST_CAST_TREE (arg1); + for (tsi1 = tsi_start (body1), tsi2 = tsi_start (body2); ; + tsi_next (&tsi1), tsi_next (&tsi2)) + { + /* The lists don't have the same number of statements. */ + if (tsi_end_p (tsi1) ^ tsi_end_p (tsi2)) + return false; + if (tsi_end_p (tsi1) && tsi_end_p (tsi2)) + return true; + if (!operand_equal_p (tsi_stmt (tsi1), tsi_stmt (tsi2), + flags & (OEP_LEXICOGRAPHIC + | OEP_NO_HASH_CHECK))) + return false; + } + } + return false; + + case tcc_statement: + switch (TREE_CODE (arg0)) + { + case RETURN_EXPR: + if (flags & OEP_LEXICOGRAPHIC) + return OP_SAME_WITH_NULL (0); + return false; + case DEBUG_BEGIN_STMT: + if (flags & OEP_LEXICOGRAPHIC) + return true; + return false; + default: + return false; + } + + default: + return false; + } + +#undef OP_SAME +#undef OP_SAME_WITH_NULL +} + +/* Generate a hash value for an expression. This can be used iteratively + by passing a previous result as the HSTATE argument. */ + +void +operand_compare::hash_operand (const_tree t, inchash::hash &hstate, + unsigned int flags) +{ + int i; + enum tree_code code; + enum tree_code_class tclass; + + if (t == NULL_TREE || t == error_mark_node) + { + hstate.merge_hash (0); + return; + } + + STRIP_ANY_LOCATION_WRAPPER (t); + + if (!(flags & OEP_ADDRESS_OF)) + STRIP_NOPS (t); + + code = TREE_CODE (t); + + switch (code) + { + /* Alas, constants aren't shared, so we can't rely on pointer + identity. */ + case VOID_CST: + hstate.merge_hash (0); + return; + case INTEGER_CST: + gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); + for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++) + hstate.add_hwi (TREE_INT_CST_ELT (t, i)); + return; + case REAL_CST: + { + unsigned int val2; + if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t)) + val2 = rvc_zero; + else + val2 = real_hash (TREE_REAL_CST_PTR (t)); + hstate.merge_hash (val2); + return; + } + case FIXED_CST: + { + unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t)); + hstate.merge_hash (val2); + return; + } + case STRING_CST: + hstate.add ((const void *) TREE_STRING_POINTER (t), + TREE_STRING_LENGTH (t)); + return; + case COMPLEX_CST: + hash_operand (TREE_REALPART (t), hstate, flags); + hash_operand (TREE_IMAGPART (t), hstate, flags); + return; + case VECTOR_CST: + { + hstate.add_int (VECTOR_CST_NPATTERNS (t)); + hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t)); + unsigned int count = vector_cst_encoded_nelts (t); + for (unsigned int i = 0; i < count; ++i) + hash_operand (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags); + return; + } + case SSA_NAME: + /* We can just compare by pointer. */ + hstate.add_hwi (SSA_NAME_VERSION (t)); + return; + case PLACEHOLDER_EXPR: + /* The node itself doesn't matter. */ + return; + case BLOCK: + case OMP_CLAUSE: + /* Ignore. */ + return; + case TREE_LIST: + /* A list of expressions, for a CALL_EXPR or as the elements of a + VECTOR_CST. */ + for (; t; t = TREE_CHAIN (t)) + hash_operand (TREE_VALUE (t), hstate, flags); + return; + case CONSTRUCTOR: + { + unsigned HOST_WIDE_INT idx; + tree field, value; + flags &= ~OEP_ADDRESS_OF; + hstate.add_int (CONSTRUCTOR_NO_CLEARING (t)); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value) + { + /* In GIMPLE the indexes can be either NULL or matching i. */ + if (field == NULL_TREE) + field = bitsize_int (idx); + hash_operand (field, hstate, flags); + hash_operand (value, hstate, flags); + } + return; + } + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (CONST_CAST_TREE (t)); + !tsi_end_p (i); tsi_next (&i)) + hash_operand (tsi_stmt (i), hstate, flags); + return; + } + case TREE_VEC: + for (i = 0; i < TREE_VEC_LENGTH (t); ++i) + hash_operand (TREE_VEC_ELT (t, i), hstate, flags); + return; + case IDENTIFIER_NODE: + hstate.add_object (IDENTIFIER_HASH_VALUE (t)); + return; + case FUNCTION_DECL: + /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form. + Otherwise nodes that compare equal according to operand_equal_p might + get different hash codes. However, don't do this for machine specific + or front end builtins, since the function code is overloaded in those + cases. */ + if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL + && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t))) + { + t = builtin_decl_explicit (DECL_FUNCTION_CODE (t)); + code = TREE_CODE (t); + } + /* FALL THROUGH */ + default: + if (POLY_INT_CST_P (t)) + { + for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) + hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i))); + return; + } + tclass = TREE_CODE_CLASS (code); + + if (tclass == tcc_declaration) + { + /* DECL's have a unique ID */ + hstate.add_hwi (DECL_UID (t)); + } + else if (tclass == tcc_comparison && !commutative_tree_code (code)) + { + /* For comparisons that can be swapped, use the lower + tree code. */ + enum tree_code ccode = swap_tree_comparison (code); + if (code < ccode) + ccode = code; + hstate.add_object (ccode); + hash_operand (TREE_OPERAND (t, ccode != code), hstate, flags); + hash_operand (TREE_OPERAND (t, ccode == code), hstate, flags); + } + else if (CONVERT_EXPR_CODE_P (code)) + { + /* NOP_EXPR and CONVERT_EXPR are considered equal by + operand_equal_p. */ + enum tree_code ccode = NOP_EXPR; + hstate.add_object (ccode); + + /* Don't hash the type, that can lead to having nodes which + compare equal according to operand_equal_p, but which + have different hash codes. Make sure to include signedness + in the hash computation. */ + hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t))); + hash_operand (TREE_OPERAND (t, 0), hstate, flags); + } + /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl. */ + else if (code == MEM_REF + && (flags & OEP_ADDRESS_OF) != 0 + && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR + && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) + && integer_zerop (TREE_OPERAND (t, 1))) + hash_operand (TREE_OPERAND (TREE_OPERAND (t, 0), 0), + hstate, flags); + /* Don't ICE on FE specific trees, or their arguments etc. + during operand_equal_p hash verification. */ + else if (!IS_EXPR_CODE_CLASS (tclass)) + gcc_assert (flags & OEP_HASH_CHECK); + else + { + unsigned int sflags = flags; + + hstate.add_object (code); + + switch (code) + { + case ADDR_EXPR: + gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); + flags |= OEP_ADDRESS_OF; + sflags = flags; + break; + + case INDIRECT_REF: + case MEM_REF: + case TARGET_MEM_REF: + flags &= ~OEP_ADDRESS_OF; + sflags = flags; + break; + + case COMPONENT_REF: + if (sflags & OEP_ADDRESS_OF) + { + hash_operand (TREE_OPERAND (t, 0), hstate, flags); + if (TREE_OPERAND (t, 2)) + hash_operand (TREE_OPERAND (t, 2), hstate, + flags & ~OEP_ADDRESS_OF); + else + { + tree field = TREE_OPERAND (t, 1); + hash_operand (DECL_FIELD_OFFSET (field), + hstate, flags & ~OEP_ADDRESS_OF); + hash_operand (DECL_FIELD_BIT_OFFSET (field), + hstate, flags & ~OEP_ADDRESS_OF); + } + return; + } + break; + case ARRAY_REF: + case ARRAY_RANGE_REF: + case BIT_FIELD_REF: + sflags &= ~OEP_ADDRESS_OF; + break; + + case COND_EXPR: + flags &= ~OEP_ADDRESS_OF; + break; + + case WIDEN_MULT_PLUS_EXPR: + case WIDEN_MULT_MINUS_EXPR: + { + /* The multiplication operands are commutative. */ + inchash::hash one, two; + hash_operand (TREE_OPERAND (t, 0), one, flags); + hash_operand (TREE_OPERAND (t, 1), two, flags); + hstate.add_commutative (one, two); + hash_operand (TREE_OPERAND (t, 2), two, flags); + return; + } + + case CALL_EXPR: + if (CALL_EXPR_FN (t) == NULL_TREE) + hstate.add_int (CALL_EXPR_IFN (t)); + break; + + case TARGET_EXPR: + /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT. + Usually different TARGET_EXPRs just should use + different temporaries in their slots. */ + hash_operand (TARGET_EXPR_SLOT (t), hstate, flags); + return; + + case OBJ_TYPE_REF: + /* Virtual table reference. */ + inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags); + flags &= ~OEP_ADDRESS_OF; + inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags); + inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags); + if (!virtual_method_call_p (t)) + return; + if (tree c = obj_type_ref_class (t)) + { + c = TYPE_NAME (TYPE_MAIN_VARIANT (c)); + /* We compute mangled names only when free_lang_data is run. + In that case we can hash precisely. */ + if (TREE_CODE (c) == TYPE_DECL + && DECL_ASSEMBLER_NAME_SET_P (c)) + hstate.add_object + (IDENTIFIER_HASH_VALUE + (DECL_ASSEMBLER_NAME (c))); + } + return; + default: + break; + } + + /* Don't hash the type, that can lead to having nodes which + compare equal according to operand_equal_p, but which + have different hash codes. */ + if (code == NON_LVALUE_EXPR) + { + /* Make sure to include signness in the hash computation. */ + hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t))); + hash_operand (TREE_OPERAND (t, 0), hstate, flags); + } + + else if (commutative_tree_code (code)) + { + /* It's a commutative expression. We want to hash it the same + however it appears. We do this by first hashing both operands + and then rehashing based on the order of their independent + hashes. */ + inchash::hash one, two; + hash_operand (TREE_OPERAND (t, 0), one, flags); + hash_operand (TREE_OPERAND (t, 1), two, flags); + hstate.add_commutative (one, two); + } + else + for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i) + hash_operand (TREE_OPERAND (t, i), hstate, + i == 0 ? flags : sflags); + } + return; + } +} + +bool +operand_compare::verify_hash_value (const_tree arg0, const_tree arg1, + unsigned int flags, bool *ret) +{ + /* When checking and unless comparing DECL names, verify that if + the outermost operand_equal_p call returns non-zero then ARG0 + and ARG1 have the same hash value. */ + if (flag_checking && !(flags & OEP_NO_HASH_CHECK)) + { + if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK)) + { + if (arg0 != arg1 && !(flags & OEP_DECL_NAME)) + { + inchash::hash hstate0 (0), hstate1 (0); + hash_operand (arg0, hstate0, flags | OEP_HASH_CHECK); + hash_operand (arg1, hstate1, flags | OEP_HASH_CHECK); + hashval_t h0 = hstate0.end (); + hashval_t h1 = hstate1.end (); + gcc_assert (h0 == h1); + } + *ret = true; + } + else + *ret = false; + + return true; + } + + return false; +} + + +static operand_compare default_compare_instance; + +/* Conveinece wrapper around operand_compare class because usually we do + not need to play with the valueizer. */ + +bool +operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) +{ + return default_compare_instance.operand_equal_p (arg0, arg1, flags); +} + +namespace inchash +{ + +/* Generate a hash value for an expression. This can be used iteratively + by passing a previous result as the HSTATE argument. + + This function is intended to produce the same hash for expressions which + would compare equal using operand_equal_p. */ +void +add_expr (const_tree t, inchash::hash &hstate, unsigned int flags) +{ + default_compare_instance.hash_operand (t, hstate, flags); +} + +} + +/* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1 + with a different signedness or a narrower precision. */ + +static bool +operand_equal_for_comparison_p (tree arg0, tree arg1) +{ + if (operand_equal_p (arg0, arg1, 0)) + return true; + + if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + || ! INTEGRAL_TYPE_P (TREE_TYPE (arg1))) + return false; + + /* Discard any conversions that don't change the modes of ARG0 and ARG1 + and see if the inner values are the same. This removes any + signedness comparison, which doesn't matter here. */ + tree op0 = arg0; + tree op1 = arg1; + STRIP_NOPS (op0); + STRIP_NOPS (op1); + if (operand_equal_p (op0, op1, 0)) + return true; + + /* Discard a single widening conversion from ARG1 and see if the inner + value is the same as ARG0. */ + if (CONVERT_EXPR_P (arg1) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0))) + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))) + < TYPE_PRECISION (TREE_TYPE (arg1)) + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return true; + + return false; +} + +/* See if ARG is an expression that is either a comparison or is performing + arithmetic on comparisons. The comparisons must only be comparing + two different values, which will be stored in *CVAL1 and *CVAL2; if + they are nonzero it means that some operands have already been found. + No variables may be used anywhere else in the expression except in the + comparisons. + + If this is true, return 1. Otherwise, return zero. */ + +static bool +twoval_comparison_p (tree arg, tree *cval1, tree *cval2) +{ + enum tree_code code = TREE_CODE (arg); + enum tree_code_class tclass = TREE_CODE_CLASS (code); + + /* We can handle some of the tcc_expression cases here. */ + if (tclass == tcc_expression && code == TRUTH_NOT_EXPR) + tclass = tcc_unary; + else if (tclass == tcc_expression + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR + || code == COMPOUND_EXPR)) + tclass = tcc_binary; + + switch (tclass) + { + case tcc_unary: + return twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2); + + case tcc_binary: + return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2) + && twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2)); + + case tcc_constant: + return true; + + case tcc_expression: + if (code == COND_EXPR) + return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2) + && twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2) + && twoval_comparison_p (TREE_OPERAND (arg, 2), cval1, cval2)); + return false; + + case tcc_comparison: + /* First see if we can handle the first operand, then the second. For + the second operand, we know *CVAL1 can't be zero. It must be that + one side of the comparison is each of the values; test for the + case where this isn't true by failing if the two operands + are the same. */ + + if (operand_equal_p (TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1), 0)) + return false; + + if (*cval1 == 0) + *cval1 = TREE_OPERAND (arg, 0); + else if (operand_equal_p (*cval1, TREE_OPERAND (arg, 0), 0)) + ; + else if (*cval2 == 0) + *cval2 = TREE_OPERAND (arg, 0); + else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 0), 0)) + ; + else + return false; + + if (operand_equal_p (*cval1, TREE_OPERAND (arg, 1), 0)) + ; + else if (*cval2 == 0) + *cval2 = TREE_OPERAND (arg, 1); + else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 1), 0)) + ; + else + return false; + + return true; + + default: + return false; + } +} + +/* ARG is a tree that is known to contain just arithmetic operations and + comparisons. Evaluate the operations in the tree substituting NEW0 for + any occurrence of OLD0 as an operand of a comparison and likewise for + NEW1 and OLD1. */ + +static tree +eval_subst (location_t loc, tree arg, tree old0, tree new0, + tree old1, tree new1) +{ + tree type = TREE_TYPE (arg); + enum tree_code code = TREE_CODE (arg); + enum tree_code_class tclass = TREE_CODE_CLASS (code); + + /* We can handle some of the tcc_expression cases here. */ + if (tclass == tcc_expression && code == TRUTH_NOT_EXPR) + tclass = tcc_unary; + else if (tclass == tcc_expression + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) + tclass = tcc_binary; + + switch (tclass) + { + case tcc_unary: + return fold_build1_loc (loc, code, type, + eval_subst (loc, TREE_OPERAND (arg, 0), + old0, new0, old1, new1)); + + case tcc_binary: + return fold_build2_loc (loc, code, type, + eval_subst (loc, TREE_OPERAND (arg, 0), + old0, new0, old1, new1), + eval_subst (loc, TREE_OPERAND (arg, 1), + old0, new0, old1, new1)); + + case tcc_expression: + switch (code) + { + case SAVE_EXPR: + return eval_subst (loc, TREE_OPERAND (arg, 0), old0, new0, + old1, new1); + + case COMPOUND_EXPR: + return eval_subst (loc, TREE_OPERAND (arg, 1), old0, new0, + old1, new1); + + case COND_EXPR: + return fold_build3_loc (loc, code, type, + eval_subst (loc, TREE_OPERAND (arg, 0), + old0, new0, old1, new1), + eval_subst (loc, TREE_OPERAND (arg, 1), + old0, new0, old1, new1), + eval_subst (loc, TREE_OPERAND (arg, 2), + old0, new0, old1, new1)); + default: + break; + } + /* Fall through - ??? */ + + case tcc_comparison: + { + tree arg0 = TREE_OPERAND (arg, 0); + tree arg1 = TREE_OPERAND (arg, 1); + + /* We need to check both for exact equality and tree equality. The + former will be true if the operand has a side-effect. In that + case, we know the operand occurred exactly once. */ + + if (arg0 == old0 || operand_equal_p (arg0, old0, 0)) + arg0 = new0; + else if (arg0 == old1 || operand_equal_p (arg0, old1, 0)) + arg0 = new1; + + if (arg1 == old0 || operand_equal_p (arg1, old0, 0)) + arg1 = new0; + else if (arg1 == old1 || operand_equal_p (arg1, old1, 0)) + arg1 = new1; + + return fold_build2_loc (loc, code, type, arg0, arg1); + } + + default: + return arg; + } +} + +/* Return a tree for the case when the result of an expression is RESULT + converted to TYPE and OMITTED was previously an operand of the expression + but is now not needed (e.g., we folded OMITTED * 0). + + If OMITTED has side effects, we must evaluate it. Otherwise, just do + the conversion of RESULT to TYPE. */ + +tree +omit_one_operand_loc (location_t loc, tree type, tree result, tree omitted) +{ + tree t = fold_convert_loc (loc, type, result); + + /* If the resulting operand is an empty statement, just return the omitted + statement casted to void. */ + if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted)) + return build1_loc (loc, NOP_EXPR, void_type_node, + fold_ignored_result (omitted)); + + if (TREE_SIDE_EFFECTS (omitted)) + return build2_loc (loc, COMPOUND_EXPR, type, + fold_ignored_result (omitted), t); + + return non_lvalue_loc (loc, t); +} + +/* Return a tree for the case when the result of an expression is RESULT + converted to TYPE and OMITTED1 and OMITTED2 were previously operands + of the expression but are now not needed. + + If OMITTED1 or OMITTED2 has side effects, they must be evaluated. + If both OMITTED1 and OMITTED2 have side effects, OMITTED1 is + evaluated before OMITTED2. Otherwise, if neither has side effects, + just do the conversion of RESULT to TYPE. */ + +tree +omit_two_operands_loc (location_t loc, tree type, tree result, + tree omitted1, tree omitted2) +{ + tree t = fold_convert_loc (loc, type, result); + + if (TREE_SIDE_EFFECTS (omitted2)) + t = build2_loc (loc, COMPOUND_EXPR, type, omitted2, t); + if (TREE_SIDE_EFFECTS (omitted1)) + t = build2_loc (loc, COMPOUND_EXPR, type, omitted1, t); + + return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue_loc (loc, t) : t; +} + + +/* Return a simplified tree node for the truth-negation of ARG. This + never alters ARG itself. We assume that ARG is an operation that + returns a truth value (0 or 1). + + FIXME: one would think we would fold the result, but it causes + problems with the dominator optimizer. */ + +static tree +fold_truth_not_expr (location_t loc, tree arg) +{ + tree type = TREE_TYPE (arg); + enum tree_code code = TREE_CODE (arg); + location_t loc1, loc2; + + /* If this is a comparison, we can simply invert it, except for + floating-point non-equality comparisons, in which case we just + enclose a TRUTH_NOT_EXPR around what we have. */ + + if (TREE_CODE_CLASS (code) == tcc_comparison) + { + tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0)); + if (FLOAT_TYPE_P (op_type) + && flag_trapping_math + && code != ORDERED_EXPR && code != UNORDERED_EXPR + && code != NE_EXPR && code != EQ_EXPR) + return NULL_TREE; + + code = invert_tree_comparison (code, HONOR_NANS (op_type)); + if (code == ERROR_MARK) + return NULL_TREE; + + tree ret = build2_loc (loc, code, type, TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1)); + copy_warning (ret, arg); + return ret; + } + + switch (code) + { + case INTEGER_CST: + return constant_boolean_node (integer_zerop (arg), type); + + case TRUTH_AND_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); + return build2_loc (loc, TRUTH_OR_EXPR, type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), + invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); + + case TRUTH_OR_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); + return build2_loc (loc, TRUTH_AND_EXPR, type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), + invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); + + case TRUTH_XOR_EXPR: + /* Here we can invert either operand. We invert the first operand + unless the second operand is a TRUTH_NOT_EXPR in which case our + result is the XOR of the first operand with the inside of the + negation of the second operand. */ + + if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR) + return build2_loc (loc, TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0), + TREE_OPERAND (TREE_OPERAND (arg, 1), 0)); + else + return build2_loc (loc, TRUTH_XOR_EXPR, type, + invert_truthvalue_loc (loc, TREE_OPERAND (arg, 0)), + TREE_OPERAND (arg, 1)); + + case TRUTH_ANDIF_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); + return build2_loc (loc, TRUTH_ORIF_EXPR, type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), + invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); + + case TRUTH_ORIF_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); + return build2_loc (loc, TRUTH_ANDIF_EXPR, type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), + invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); + + case TRUTH_NOT_EXPR: + return TREE_OPERAND (arg, 0); + + case COND_EXPR: + { + tree arg1 = TREE_OPERAND (arg, 1); + tree arg2 = TREE_OPERAND (arg, 2); + + loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc); + loc2 = expr_location_or (TREE_OPERAND (arg, 2), loc); + + /* A COND_EXPR may have a throw as one operand, which + then has void type. Just leave void operands + as they are. */ + return build3_loc (loc, COND_EXPR, type, TREE_OPERAND (arg, 0), + VOID_TYPE_P (TREE_TYPE (arg1)) + ? arg1 : invert_truthvalue_loc (loc1, arg1), + VOID_TYPE_P (TREE_TYPE (arg2)) + ? arg2 : invert_truthvalue_loc (loc2, arg2)); + } + + case COMPOUND_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc); + return build2_loc (loc, COMPOUND_EXPR, type, + TREE_OPERAND (arg, 0), + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 1))); + + case NON_LVALUE_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + return invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)); + + CASE_CONVERT: + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); + + /* fall through */ + + case FLOAT_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + return build1_loc (loc, TREE_CODE (arg), type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); + + case BIT_AND_EXPR: + if (!integer_onep (TREE_OPERAND (arg, 1))) + return NULL_TREE; + return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, 0)); + + case SAVE_EXPR: + return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); + + case CLEANUP_POINT_EXPR: + loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); + return build1_loc (loc, CLEANUP_POINT_EXPR, type, + invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); + + default: + return NULL_TREE; + } +} + +/* Fold the truth-negation of ARG. This never alters ARG itself. We + assume that ARG is an operation that returns a truth value (0 or 1 + for scalars, 0 or -1 for vectors). Return the folded expression if + folding is successful. Otherwise, return NULL_TREE. */ + +static tree +fold_invert_truthvalue (location_t loc, tree arg) +{ + tree type = TREE_TYPE (arg); + return fold_unary_loc (loc, VECTOR_TYPE_P (type) + ? BIT_NOT_EXPR + : TRUTH_NOT_EXPR, + type, arg); +} + +/* Return a simplified tree node for the truth-negation of ARG. This + never alters ARG itself. We assume that ARG is an operation that + returns a truth value (0 or 1 for scalars, 0 or -1 for vectors). */ + +tree +invert_truthvalue_loc (location_t loc, tree arg) +{ + if (TREE_CODE (arg) == ERROR_MARK) + return arg; + + tree type = TREE_TYPE (arg); + return fold_build1_loc (loc, VECTOR_TYPE_P (type) + ? BIT_NOT_EXPR + : TRUTH_NOT_EXPR, + type, arg); +} + +/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER + starting at BITPOS. The field is unsigned if UNSIGNEDP is nonzero + and uses reverse storage order if REVERSEP is nonzero. ORIG_INNER + is the original memory reference used to preserve the alias set of + the access. */ + +static tree +make_bit_field_ref (location_t loc, tree inner, tree orig_inner, tree type, + HOST_WIDE_INT bitsize, poly_int64 bitpos, + int unsignedp, int reversep) +{ + tree result, bftype; + + /* Attempt not to lose the access path if possible. */ + if (TREE_CODE (orig_inner) == COMPONENT_REF) + { + tree ninner = TREE_OPERAND (orig_inner, 0); + machine_mode nmode; + poly_int64 nbitsize, nbitpos; + tree noffset; + int nunsignedp, nreversep, nvolatilep = 0; + tree base = get_inner_reference (ninner, &nbitsize, &nbitpos, + &noffset, &nmode, &nunsignedp, + &nreversep, &nvolatilep); + if (base == inner + && noffset == NULL_TREE + && known_subrange_p (bitpos, bitsize, nbitpos, nbitsize) + && !reversep + && !nreversep + && !nvolatilep) + { + inner = ninner; + bitpos -= nbitpos; + } + } + + alias_set_type iset = get_alias_set (orig_inner); + if (iset == 0 && get_alias_set (inner) != iset) + inner = fold_build2 (MEM_REF, TREE_TYPE (inner), + build_fold_addr_expr (inner), + build_int_cst (ptr_type_node, 0)); + + if (known_eq (bitpos, 0) && !reversep) + { + tree size = TYPE_SIZE (TREE_TYPE (inner)); + if ((INTEGRAL_TYPE_P (TREE_TYPE (inner)) + || POINTER_TYPE_P (TREE_TYPE (inner))) + && tree_fits_shwi_p (size) + && tree_to_shwi (size) == bitsize) + return fold_convert_loc (loc, type, inner); + } + + bftype = type; + if (TYPE_PRECISION (bftype) != bitsize + || TYPE_UNSIGNED (bftype) == !unsignedp) + bftype = build_nonstandard_integer_type (bitsize, 0); + + result = build3_loc (loc, BIT_FIELD_REF, bftype, inner, + bitsize_int (bitsize), bitsize_int (bitpos)); + REF_REVERSE_STORAGE_ORDER (result) = reversep; + + if (bftype != type) + result = fold_convert_loc (loc, type, result); + + return result; +} + +/* Optimize a bit-field compare. + + There are two cases: First is a compare against a constant and the + second is a comparison of two items where the fields are at the same + bit position relative to the start of a chunk (byte, halfword, word) + large enough to contain it. In these cases we can avoid the shift + implicit in bitfield extractions. + + For constants, we emit a compare of the shifted constant with the + BIT_AND_EXPR of a mask and a byte, halfword, or word of the operand being + compared. For two fields at the same position, we do the ANDs with the + similar mask and compare the result of the ANDs. + + CODE is the comparison code, known to be either NE_EXPR or EQ_EXPR. + COMPARE_TYPE is the type of the comparison, and LHS and RHS + are the left and right operands of the comparison, respectively. + + If the optimization described above can be done, we return the resulting + tree. Otherwise we return zero. */ + +static tree +optimize_bit_field_compare (location_t loc, enum tree_code code, + tree compare_type, tree lhs, tree rhs) +{ + poly_int64 plbitpos, plbitsize, rbitpos, rbitsize; + HOST_WIDE_INT lbitpos, lbitsize, nbitpos, nbitsize; + tree type = TREE_TYPE (lhs); + tree unsigned_type; + int const_p = TREE_CODE (rhs) == INTEGER_CST; + machine_mode lmode, rmode; + scalar_int_mode nmode; + int lunsignedp, runsignedp; + int lreversep, rreversep; + int lvolatilep = 0, rvolatilep = 0; + tree linner, rinner = NULL_TREE; + tree mask; + tree offset; + + /* Get all the information about the extractions being done. If the bit size + is the same as the size of the underlying object, we aren't doing an + extraction at all and so can do nothing. We also don't want to + do anything if the inner expression is a PLACEHOLDER_EXPR since we + then will no longer be able to replace it. */ + linner = get_inner_reference (lhs, &plbitsize, &plbitpos, &offset, &lmode, + &lunsignedp, &lreversep, &lvolatilep); + if (linner == lhs + || !known_size_p (plbitsize) + || !plbitsize.is_constant (&lbitsize) + || !plbitpos.is_constant (&lbitpos) + || known_eq (lbitsize, GET_MODE_BITSIZE (lmode)) + || offset != 0 + || TREE_CODE (linner) == PLACEHOLDER_EXPR + || lvolatilep) + return 0; + + if (const_p) + rreversep = lreversep; + else + { + /* If this is not a constant, we can only do something if bit positions, + sizes, signedness and storage order are the same. */ + rinner + = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode, + &runsignedp, &rreversep, &rvolatilep); + + if (rinner == rhs + || maybe_ne (lbitpos, rbitpos) + || maybe_ne (lbitsize, rbitsize) + || lunsignedp != runsignedp + || lreversep != rreversep + || offset != 0 + || TREE_CODE (rinner) == PLACEHOLDER_EXPR + || rvolatilep) + return 0; + } + + /* Honor the C++ memory model and mimic what RTL expansion does. */ + poly_uint64 bitstart = 0; + poly_uint64 bitend = 0; + if (TREE_CODE (lhs) == COMPONENT_REF) + { + get_bit_range (&bitstart, &bitend, lhs, &plbitpos, &offset); + if (!plbitpos.is_constant (&lbitpos) || offset != NULL_TREE) + return 0; + } + + /* See if we can find a mode to refer to this field. We should be able to, + but fail if we can't. */ + if (!get_best_mode (lbitsize, lbitpos, bitstart, bitend, + const_p ? TYPE_ALIGN (TREE_TYPE (linner)) + : MIN (TYPE_ALIGN (TREE_TYPE (linner)), + TYPE_ALIGN (TREE_TYPE (rinner))), + BITS_PER_WORD, false, &nmode)) + return 0; + + /* Set signed and unsigned types of the precision of this mode for the + shifts below. */ + unsigned_type = lang_hooks.types.type_for_mode (nmode, 1); + + /* Compute the bit position and size for the new reference and our offset + within it. If the new reference is the same size as the original, we + won't optimize anything, so return zero. */ + nbitsize = GET_MODE_BITSIZE (nmode); + nbitpos = lbitpos & ~ (nbitsize - 1); + lbitpos -= nbitpos; + if (nbitsize == lbitsize) + return 0; + + if (lreversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) + lbitpos = nbitsize - lbitsize - lbitpos; + + /* Make the mask to be used against the extracted field. */ + mask = build_int_cst_type (unsigned_type, -1); + mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize)); + mask = const_binop (RSHIFT_EXPR, mask, + size_int (nbitsize - lbitsize - lbitpos)); + + if (! const_p) + { + if (nbitpos < 0) + return 0; + + /* If not comparing with constant, just rework the comparison + and return. */ + tree t1 = make_bit_field_ref (loc, linner, lhs, unsigned_type, + nbitsize, nbitpos, 1, lreversep); + t1 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t1, mask); + tree t2 = make_bit_field_ref (loc, rinner, rhs, unsigned_type, + nbitsize, nbitpos, 1, rreversep); + t2 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t2, mask); + return fold_build2_loc (loc, code, compare_type, t1, t2); + } + + /* Otherwise, we are handling the constant case. See if the constant is too + big for the field. Warn and return a tree for 0 (false) if so. We do + this not only for its own sake, but to avoid having to test for this + error case below. If we didn't, we might generate wrong code. + + For unsigned fields, the constant shifted right by the field length should + be all zero. For signed fields, the high-order bits should agree with + the sign bit. */ + + if (lunsignedp) + { + if (wi::lrshift (wi::to_wide (rhs), lbitsize) != 0) + { + warning (0, "comparison is always %d due to width of bit-field", + code == NE_EXPR); + return constant_boolean_node (code == NE_EXPR, compare_type); + } + } + else + { + wide_int tem = wi::arshift (wi::to_wide (rhs), lbitsize - 1); + if (tem != 0 && tem != -1) + { + warning (0, "comparison is always %d due to width of bit-field", + code == NE_EXPR); + return constant_boolean_node (code == NE_EXPR, compare_type); + } + } + + if (nbitpos < 0) + return 0; + + /* Single-bit compares should always be against zero. */ + if (lbitsize == 1 && ! integer_zerop (rhs)) + { + code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR; + rhs = build_int_cst (type, 0); + } + + /* Make a new bitfield reference, shift the constant over the + appropriate number of bits and mask it with the computed mask + (in case this was a signed field). If we changed it, make a new one. */ + lhs = make_bit_field_ref (loc, linner, lhs, unsigned_type, + nbitsize, nbitpos, 1, lreversep); + + rhs = const_binop (BIT_AND_EXPR, + const_binop (LSHIFT_EXPR, + fold_convert_loc (loc, unsigned_type, rhs), + size_int (lbitpos)), + mask); + + lhs = build2_loc (loc, code, compare_type, + build2 (BIT_AND_EXPR, unsigned_type, lhs, mask), rhs); + return lhs; +} + +/* Subroutine for fold_truth_andor_1: decode a field reference. + + If EXP is a comparison reference, we return the innermost reference. + + *PBITSIZE is set to the number of bits in the reference, *PBITPOS is + set to the starting bit number. + + If the innermost field can be completely contained in a mode-sized + unit, *PMODE is set to that mode. Otherwise, it is set to VOIDmode. + + *PVOLATILEP is set to 1 if the any expression encountered is volatile; + otherwise it is not changed. + + *PUNSIGNEDP is set to the signedness of the field. + + *PREVERSEP is set to the storage order of the field. + + *PMASK is set to the mask used. This is either contained in a + BIT_AND_EXPR or derived from the width of the field. + + *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any. + + Return 0 if this is not a component reference or is one that we can't + do anything with. */ + +static tree +decode_field_reference (location_t loc, tree *exp_, HOST_WIDE_INT *pbitsize, + HOST_WIDE_INT *pbitpos, machine_mode *pmode, + int *punsignedp, int *preversep, int *pvolatilep, + tree *pmask, tree *pand_mask) +{ + tree exp = *exp_; + tree outer_type = 0; + tree and_mask = 0; + tree mask, inner, offset; + tree unsigned_type; + unsigned int precision; + + /* All the optimizations using this function assume integer fields. + There are problems with FP fields since the type_for_size call + below can fail for, e.g., XFmode. */ + if (! INTEGRAL_TYPE_P (TREE_TYPE (exp))) + return NULL_TREE; + + /* We are interested in the bare arrangement of bits, so strip everything + that doesn't affect the machine mode. However, record the type of the + outermost expression if it may matter below. */ + if (CONVERT_EXPR_P (exp) + || TREE_CODE (exp) == NON_LVALUE_EXPR) + outer_type = TREE_TYPE (exp); + STRIP_NOPS (exp); + + if (TREE_CODE (exp) == BIT_AND_EXPR) + { + and_mask = TREE_OPERAND (exp, 1); + exp = TREE_OPERAND (exp, 0); + STRIP_NOPS (exp); STRIP_NOPS (and_mask); + if (TREE_CODE (and_mask) != INTEGER_CST) + return NULL_TREE; + } + + poly_int64 poly_bitsize, poly_bitpos; + inner = get_inner_reference (exp, &poly_bitsize, &poly_bitpos, &offset, + pmode, punsignedp, preversep, pvolatilep); + if ((inner == exp && and_mask == 0) + || !poly_bitsize.is_constant (pbitsize) + || !poly_bitpos.is_constant (pbitpos) + || *pbitsize < 0 + || offset != 0 + || TREE_CODE (inner) == PLACEHOLDER_EXPR + /* Reject out-of-bound accesses (PR79731). */ + || (! AGGREGATE_TYPE_P (TREE_TYPE (inner)) + && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)), + *pbitpos + *pbitsize) < 0)) + return NULL_TREE; + + unsigned_type = lang_hooks.types.type_for_size (*pbitsize, 1); + if (unsigned_type == NULL_TREE) + return NULL_TREE; + + *exp_ = exp; + + /* If the number of bits in the reference is the same as the bitsize of + the outer type, then the outer type gives the signedness. Otherwise + (in case of a small bitfield) the signedness is unchanged. */ + if (outer_type && *pbitsize == TYPE_PRECISION (outer_type)) + *punsignedp = TYPE_UNSIGNED (outer_type); + + /* Compute the mask to access the bitfield. */ + precision = TYPE_PRECISION (unsigned_type); + + mask = build_int_cst_type (unsigned_type, -1); + + mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize)); + mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize)); + + /* Merge it with the mask we found in the BIT_AND_EXPR, if any. */ + if (and_mask != 0) + mask = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, + fold_convert_loc (loc, unsigned_type, and_mask), mask); + + *pmask = mask; + *pand_mask = and_mask; + return inner; +} + +/* Return nonzero if MASK represents a mask of SIZE ones in the low-order + bit positions and MASK is SIGNED. */ + +static bool +all_ones_mask_p (const_tree mask, unsigned int size) +{ + tree type = TREE_TYPE (mask); + unsigned int precision = TYPE_PRECISION (type); + + /* If this function returns true when the type of the mask is + UNSIGNED, then there will be errors. In particular see + gcc.c-torture/execute/990326-1.c. There does not appear to be + any documentation paper trail as to why this is so. But the pre + wide-int worked with that restriction and it has been preserved + here. */ + if (size > precision || TYPE_SIGN (type) == UNSIGNED) + return false; + + return wi::mask (size, false, precision) == wi::to_wide (mask); +} + +/* Subroutine for fold: determine if VAL is the INTEGER_CONST that + represents the sign bit of EXP's type. If EXP represents a sign + or zero extension, also test VAL against the unextended type. + The return value is the (sub)expression whose sign bit is VAL, + or NULL_TREE otherwise. */ + +tree +sign_bit_p (tree exp, const_tree val) +{ + int width; + tree t; + + /* Tree EXP must have an integral type. */ + t = TREE_TYPE (exp); + if (! INTEGRAL_TYPE_P (t)) + return NULL_TREE; + + /* Tree VAL must be an integer constant. */ + if (TREE_CODE (val) != INTEGER_CST + || TREE_OVERFLOW (val)) + return NULL_TREE; + + width = TYPE_PRECISION (t); + if (wi::only_sign_bit_p (wi::to_wide (val), width)) + return exp; + + /* Handle extension from a narrower type. */ + if (TREE_CODE (exp) == NOP_EXPR + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))) < width) + return sign_bit_p (TREE_OPERAND (exp, 0), val); + + return NULL_TREE; +} + +/* Subroutine for fold_truth_andor_1: determine if an operand is simple enough + to be evaluated unconditionally. */ + +static bool +simple_operand_p (const_tree exp) +{ + /* Strip any conversions that don't change the machine mode. */ + STRIP_NOPS (exp); + + return (CONSTANT_CLASS_P (exp) + || TREE_CODE (exp) == SSA_NAME + || (DECL_P (exp) + && ! TREE_ADDRESSABLE (exp) + && ! TREE_THIS_VOLATILE (exp) + && ! DECL_NONLOCAL (exp) + /* Don't regard global variables as simple. They may be + allocated in ways unknown to the compiler (shared memory, + #pragma weak, etc). */ + && ! TREE_PUBLIC (exp) + && ! DECL_EXTERNAL (exp) + /* Weakrefs are not safe to be read, since they can be NULL. + They are !TREE_PUBLIC && !DECL_EXTERNAL but still + have DECL_WEAK flag set. */ + && (! VAR_OR_FUNCTION_DECL_P (exp) || ! DECL_WEAK (exp)) + /* Loading a static variable is unduly expensive, but global + registers aren't expensive. */ + && (! TREE_STATIC (exp) || DECL_REGISTER (exp)))); +} + +/* Subroutine for fold_truth_andor: determine if an operand is simple enough + to be evaluated unconditionally. + I addition to simple_operand_p, we assume that comparisons, conversions, + and logic-not operations are simple, if their operands are simple, too. */ + +static bool +simple_operand_p_2 (tree exp) +{ + enum tree_code code; + + if (TREE_SIDE_EFFECTS (exp) || generic_expr_could_trap_p (exp)) + return false; + + while (CONVERT_EXPR_P (exp)) + exp = TREE_OPERAND (exp, 0); + + code = TREE_CODE (exp); + + if (TREE_CODE_CLASS (code) == tcc_comparison) + return (simple_operand_p (TREE_OPERAND (exp, 0)) + && simple_operand_p (TREE_OPERAND (exp, 1))); + + if (code == TRUTH_NOT_EXPR) + return simple_operand_p_2 (TREE_OPERAND (exp, 0)); + + return simple_operand_p (exp); +} + + +/* The following functions are subroutines to fold_range_test and allow it to + try to change a logical combination of comparisons into a range test. + + For example, both + X == 2 || X == 3 || X == 4 || X == 5 + and + X >= 2 && X <= 5 + are converted to + (unsigned) (X - 2) <= 3 + + We describe each set of comparisons as being either inside or outside + a range, using a variable named like IN_P, and then describe the + range with a lower and upper bound. If one of the bounds is omitted, + it represents either the highest or lowest value of the type. + + In the comments below, we represent a range by two numbers in brackets + preceded by a "+" to designate being inside that range, or a "-" to + designate being outside that range, so the condition can be inverted by + flipping the prefix. An omitted bound is represented by a "-". For + example, "- [-, 10]" means being outside the range starting at the lowest + possible value and ending at 10, in other words, being greater than 10. + The range "+ [-, -]" is always true and hence the range "- [-, -]" is + always false. + + We set up things so that the missing bounds are handled in a consistent + manner so neither a missing bound nor "true" and "false" need to be + handled using a special case. */ + +/* Return the result of applying CODE to ARG0 and ARG1, but handle the case + of ARG0 and/or ARG1 being omitted, meaning an unlimited range. UPPER0_P + and UPPER1_P are nonzero if the respective argument is an upper bound + and zero for a lower. TYPE, if nonzero, is the type of the result; it + must be specified for a comparison. ARG1 will be converted to ARG0's + type if both are specified. */ + +static tree +range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, + tree arg1, int upper1_p) +{ + tree tem; + int result; + int sgn0, sgn1; + + /* If neither arg represents infinity, do the normal operation. + Else, if not a comparison, return infinity. Else handle the special + comparison rules. Note that most of the cases below won't occur, but + are handled for consistency. */ + + if (arg0 != 0 && arg1 != 0) + { + tem = fold_build2 (code, type != 0 ? type : TREE_TYPE (arg0), + arg0, fold_convert (TREE_TYPE (arg0), arg1)); + STRIP_NOPS (tem); + return TREE_CODE (tem) == INTEGER_CST ? tem : 0; + } + + if (TREE_CODE_CLASS (code) != tcc_comparison) + return 0; + + /* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0 + for neither. In real maths, we cannot assume open ended ranges are + the same. But, this is computer arithmetic, where numbers are finite. + We can therefore make the transformation of any unbounded range with + the value Z, Z being greater than any representable number. This permits + us to treat unbounded ranges as equal. */ + sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1); + sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1); + switch (code) + { + case EQ_EXPR: + result = sgn0 == sgn1; + break; + case NE_EXPR: + result = sgn0 != sgn1; + break; + case LT_EXPR: + result = sgn0 < sgn1; + break; + case LE_EXPR: + result = sgn0 <= sgn1; + break; + case GT_EXPR: + result = sgn0 > sgn1; + break; + case GE_EXPR: + result = sgn0 >= sgn1; + break; + default: + gcc_unreachable (); + } + + return constant_boolean_node (result, type); +} + +/* Helper routine for make_range. Perform one step for it, return + new expression if the loop should continue or NULL_TREE if it should + stop. */ + +tree +make_range_step (location_t loc, enum tree_code code, tree arg0, tree arg1, + tree exp_type, tree *p_low, tree *p_high, int *p_in_p, + bool *strict_overflow_p) +{ + tree arg0_type = TREE_TYPE (arg0); + tree n_low, n_high, low = *p_low, high = *p_high; + int in_p = *p_in_p, n_in_p; + + switch (code) + { + case TRUTH_NOT_EXPR: + /* We can only do something if the range is testing for zero. */ + if (low == NULL_TREE || high == NULL_TREE + || ! integer_zerop (low) || ! integer_zerop (high)) + return NULL_TREE; + *p_in_p = ! in_p; + return arg0; + + case EQ_EXPR: case NE_EXPR: + case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR: + /* We can only do something if the range is testing for zero + and if the second operand is an integer constant. Note that + saying something is "in" the range we make is done by + complementing IN_P since it will set in the initial case of + being not equal to zero; "out" is leaving it alone. */ + if (low == NULL_TREE || high == NULL_TREE + || ! integer_zerop (low) || ! integer_zerop (high) + || TREE_CODE (arg1) != INTEGER_CST) + return NULL_TREE; + + switch (code) + { + case NE_EXPR: /* - [c, c] */ + low = high = arg1; + break; + case EQ_EXPR: /* + [c, c] */ + in_p = ! in_p, low = high = arg1; + break; + case GT_EXPR: /* - [-, c] */ + low = 0, high = arg1; + break; + case GE_EXPR: /* + [c, -] */ + in_p = ! in_p, low = arg1, high = 0; + break; + case LT_EXPR: /* - [c, -] */ + low = arg1, high = 0; + break; + case LE_EXPR: /* + [-, c] */ + in_p = ! in_p, low = 0, high = arg1; + break; + default: + gcc_unreachable (); + } + + /* If this is an unsigned comparison, we also know that EXP is + greater than or equal to zero. We base the range tests we make + on that fact, so we record it here so we can parse existing + range tests. We test arg0_type since often the return type + of, e.g. EQ_EXPR, is boolean. */ + if (TYPE_UNSIGNED (arg0_type) && (low == 0 || high == 0)) + { + if (! merge_ranges (&n_in_p, &n_low, &n_high, + in_p, low, high, 1, + build_int_cst (arg0_type, 0), + NULL_TREE)) + return NULL_TREE; + + in_p = n_in_p, low = n_low, high = n_high; + + /* If the high bound is missing, but we have a nonzero low + bound, reverse the range so it goes from zero to the low bound + minus 1. */ + if (high == 0 && low && ! integer_zerop (low)) + { + in_p = ! in_p; + high = range_binop (MINUS_EXPR, NULL_TREE, low, 0, + build_int_cst (TREE_TYPE (low), 1), 0); + low = build_int_cst (arg0_type, 0); + } + } + + *p_low = low; + *p_high = high; + *p_in_p = in_p; + return arg0; + + case NEGATE_EXPR: + /* If flag_wrapv and ARG0_TYPE is signed, make sure + low and high are non-NULL, then normalize will DTRT. */ + if (!TYPE_UNSIGNED (arg0_type) + && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) + { + if (low == NULL_TREE) + low = TYPE_MIN_VALUE (arg0_type); + if (high == NULL_TREE) + high = TYPE_MAX_VALUE (arg0_type); + } + + /* (-x) IN [a,b] -> x in [-b, -a] */ + n_low = range_binop (MINUS_EXPR, exp_type, + build_int_cst (exp_type, 0), + 0, high, 1); + n_high = range_binop (MINUS_EXPR, exp_type, + build_int_cst (exp_type, 0), + 0, low, 0); + if (n_high != 0 && TREE_OVERFLOW (n_high)) + return NULL_TREE; + goto normalize; + + case BIT_NOT_EXPR: + /* ~ X -> -X - 1 */ + return build2_loc (loc, MINUS_EXPR, exp_type, negate_expr (arg0), + build_int_cst (exp_type, 1)); + + case PLUS_EXPR: + case MINUS_EXPR: + if (TREE_CODE (arg1) != INTEGER_CST) + return NULL_TREE; + + /* If flag_wrapv and ARG0_TYPE is signed, then we cannot + move a constant to the other side. */ + if (!TYPE_UNSIGNED (arg0_type) + && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) + return NULL_TREE; + + /* If EXP is signed, any overflow in the computation is undefined, + so we don't worry about it so long as our computations on + the bounds don't overflow. For unsigned, overflow is defined + and this is exactly the right thing. */ + n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, + arg0_type, low, 0, arg1, 0); + n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, + arg0_type, high, 1, arg1, 0); + if ((n_low != 0 && TREE_OVERFLOW (n_low)) + || (n_high != 0 && TREE_OVERFLOW (n_high))) + return NULL_TREE; + + if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) + *strict_overflow_p = true; + + normalize: + /* Check for an unsigned range which has wrapped around the maximum + value thus making n_high < n_low, and normalize it. */ + if (n_low && n_high && tree_int_cst_lt (n_high, n_low)) + { + low = range_binop (PLUS_EXPR, arg0_type, n_high, 0, + build_int_cst (TREE_TYPE (n_high), 1), 0); + high = range_binop (MINUS_EXPR, arg0_type, n_low, 0, + build_int_cst (TREE_TYPE (n_low), 1), 0); + + /* If the range is of the form +/- [ x+1, x ], we won't + be able to normalize it. But then, it represents the + whole range or the empty set, so make it + +/- [ -, - ]. */ + if (tree_int_cst_equal (n_low, low) + && tree_int_cst_equal (n_high, high)) + low = high = 0; + else + in_p = ! in_p; + } + else + low = n_low, high = n_high; + + *p_low = low; + *p_high = high; + *p_in_p = in_p; + return arg0; + + CASE_CONVERT: + case NON_LVALUE_EXPR: + if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type)) + return NULL_TREE; + + if (! INTEGRAL_TYPE_P (arg0_type) + || (low != 0 && ! int_fits_type_p (low, arg0_type)) + || (high != 0 && ! int_fits_type_p (high, arg0_type))) + return NULL_TREE; + + n_low = low, n_high = high; + + if (n_low != 0) + n_low = fold_convert_loc (loc, arg0_type, n_low); + + if (n_high != 0) + n_high = fold_convert_loc (loc, arg0_type, n_high); + + /* If we're converting arg0 from an unsigned type, to exp, + a signed type, we will be doing the comparison as unsigned. + The tests above have already verified that LOW and HIGH + are both positive. + + So we have to ensure that we will handle large unsigned + values the same way that the current signed bounds treat + negative values. */ + + if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type)) + { + tree high_positive; + tree equiv_type; + /* For fixed-point modes, we need to pass the saturating flag + as the 2nd parameter. */ + if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type))) + equiv_type + = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), + TYPE_SATURATING (arg0_type)); + else + equiv_type + = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), 1); + + /* A range without an upper bound is, naturally, unbounded. + Since convert would have cropped a very large value, use + the max value for the destination type. */ + high_positive + = TYPE_MAX_VALUE (equiv_type) ? TYPE_MAX_VALUE (equiv_type) + : TYPE_MAX_VALUE (arg0_type); + + if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type)) + high_positive = fold_build2_loc (loc, RSHIFT_EXPR, arg0_type, + fold_convert_loc (loc, arg0_type, + high_positive), + build_int_cst (arg0_type, 1)); + + /* If the low bound is specified, "and" the range with the + range for which the original unsigned value will be + positive. */ + if (low != 0) + { + if (! merge_ranges (&n_in_p, &n_low, &n_high, 1, n_low, n_high, + 1, fold_convert_loc (loc, arg0_type, + integer_zero_node), + high_positive)) + return NULL_TREE; + + in_p = (n_in_p == in_p); + } + else + { + /* Otherwise, "or" the range with the range of the input + that will be interpreted as negative. */ + if (! merge_ranges (&n_in_p, &n_low, &n_high, 0, n_low, n_high, + 1, fold_convert_loc (loc, arg0_type, + integer_zero_node), + high_positive)) + return NULL_TREE; + + in_p = (in_p != n_in_p); + } + } + + *p_low = n_low; + *p_high = n_high; + *p_in_p = in_p; + return arg0; + + default: + return NULL_TREE; + } +} + +/* Given EXP, a logical expression, set the range it is testing into + variables denoted by PIN_P, PLOW, and PHIGH. Return the expression + actually being tested. *PLOW and *PHIGH will be made of the same + type as the returned expression. If EXP is not a comparison, we + will most likely not be returning a useful value and range. Set + *STRICT_OVERFLOW_P to true if the return value is only valid + because signed overflow is undefined; otherwise, do not change + *STRICT_OVERFLOW_P. */ + +tree +make_range (tree exp, int *pin_p, tree *plow, tree *phigh, + bool *strict_overflow_p) +{ + enum tree_code code; + tree arg0, arg1 = NULL_TREE; + tree exp_type, nexp; + int in_p; + tree low, high; + location_t loc = EXPR_LOCATION (exp); + + /* Start with simply saying "EXP != 0" and then look at the code of EXP + and see if we can refine the range. Some of the cases below may not + happen, but it doesn't seem worth worrying about this. We "continue" + the outer loop when we've changed something; otherwise we "break" + the switch, which will "break" the while. */ + + in_p = 0; + low = high = build_int_cst (TREE_TYPE (exp), 0); + + while (1) + { + code = TREE_CODE (exp); + exp_type = TREE_TYPE (exp); + arg0 = NULL_TREE; + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) + { + if (TREE_OPERAND_LENGTH (exp) > 0) + arg0 = TREE_OPERAND (exp, 0); + if (TREE_CODE_CLASS (code) == tcc_binary + || TREE_CODE_CLASS (code) == tcc_comparison + || (TREE_CODE_CLASS (code) == tcc_expression + && TREE_OPERAND_LENGTH (exp) > 1)) + arg1 = TREE_OPERAND (exp, 1); + } + if (arg0 == NULL_TREE) + break; + + nexp = make_range_step (loc, code, arg0, arg1, exp_type, &low, + &high, &in_p, strict_overflow_p); + if (nexp == NULL_TREE) + break; + exp = nexp; + } + + /* If EXP is a constant, we can evaluate whether this is true or false. */ + if (TREE_CODE (exp) == INTEGER_CST) + { + in_p = in_p == (integer_onep (range_binop (GE_EXPR, integer_type_node, + exp, 0, low, 0)) + && integer_onep (range_binop (LE_EXPR, integer_type_node, + exp, 1, high, 1))); + low = high = 0; + exp = 0; + } + + *pin_p = in_p, *plow = low, *phigh = high; + return exp; +} + +/* Returns TRUE if [LOW, HIGH] range check can be optimized to + a bitwise check i.e. when + LOW == 0xXX...X00...0 + HIGH == 0xXX...X11...1 + Return corresponding mask in MASK and stem in VALUE. */ + +static bool +maskable_range_p (const_tree low, const_tree high, tree type, tree *mask, + tree *value) +{ + if (TREE_CODE (low) != INTEGER_CST + || TREE_CODE (high) != INTEGER_CST) + return false; + + unsigned prec = TYPE_PRECISION (type); + wide_int lo = wi::to_wide (low, prec); + wide_int hi = wi::to_wide (high, prec); + + wide_int end_mask = lo ^ hi; + if ((end_mask & (end_mask + 1)) != 0 + || (lo & end_mask) != 0) + return false; + + wide_int stem_mask = ~end_mask; + wide_int stem = lo & stem_mask; + if (stem != (hi & stem_mask)) + return false; + + *mask = wide_int_to_tree (type, stem_mask); + *value = wide_int_to_tree (type, stem); + + return true; +} + +/* Helper routine for build_range_check and match.pd. Return the type to + perform the check or NULL if it shouldn't be optimized. */ + +tree +range_check_type (tree etype) +{ + /* First make sure that arithmetics in this type is valid, then make sure + that it wraps around. */ + if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE) + etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), 1); + + if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_UNSIGNED (etype)) + { + tree utype, minv, maxv; + + /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN + for the type in question, as we rely on this here. */ + utype = unsigned_type_for (etype); + maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); + maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, + build_int_cst (TREE_TYPE (maxv), 1), 1); + minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); + + if (integer_zerop (range_binop (NE_EXPR, integer_type_node, + minv, 1, maxv, 1))) + etype = utype; + else + return NULL_TREE; + } + else if (POINTER_TYPE_P (etype) || TREE_CODE (etype) == OFFSET_TYPE) + etype = unsigned_type_for (etype); + return etype; +} + +/* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result + type, TYPE, return an expression to test if EXP is in (or out of, depending + on IN_P) the range. Return 0 if the test couldn't be created. */ + +tree +build_range_check (location_t loc, tree type, tree exp, int in_p, + tree low, tree high) +{ + tree etype = TREE_TYPE (exp), mask, value; + + /* Disable this optimization for function pointer expressions + on targets that require function pointer canonicalization. */ + if (targetm.have_canonicalize_funcptr_for_compare () + && POINTER_TYPE_P (etype) + && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (etype))) + return NULL_TREE; + + if (! in_p) + { + value = build_range_check (loc, type, exp, 1, low, high); + if (value != 0) + return invert_truthvalue_loc (loc, value); + + return 0; + } + + if (low == 0 && high == 0) + return omit_one_operand_loc (loc, type, build_int_cst (type, 1), exp); + + if (low == 0) + return fold_build2_loc (loc, LE_EXPR, type, exp, + fold_convert_loc (loc, etype, high)); + + if (high == 0) + return fold_build2_loc (loc, GE_EXPR, type, exp, + fold_convert_loc (loc, etype, low)); + + if (operand_equal_p (low, high, 0)) + return fold_build2_loc (loc, EQ_EXPR, type, exp, + fold_convert_loc (loc, etype, low)); + + if (TREE_CODE (exp) == BIT_AND_EXPR + && maskable_range_p (low, high, etype, &mask, &value)) + return fold_build2_loc (loc, EQ_EXPR, type, + fold_build2_loc (loc, BIT_AND_EXPR, etype, + exp, mask), + value); + + if (integer_zerop (low)) + { + if (! TYPE_UNSIGNED (etype)) + { + etype = unsigned_type_for (etype); + high = fold_convert_loc (loc, etype, high); + exp = fold_convert_loc (loc, etype, exp); + } + return build_range_check (loc, type, exp, 1, 0, high); + } + + /* Optimize (c>=1) && (c<=127) into (signed char)c > 0. */ + if (integer_onep (low) && TREE_CODE (high) == INTEGER_CST) + { + int prec = TYPE_PRECISION (etype); + + if (wi::mask <widest_int> (prec - 1, false) == wi::to_widest (high)) + { + if (TYPE_UNSIGNED (etype)) + { + tree signed_etype = signed_type_for (etype); + if (TYPE_PRECISION (signed_etype) != TYPE_PRECISION (etype)) + etype + = build_nonstandard_integer_type (TYPE_PRECISION (etype), 0); + else + etype = signed_etype; + exp = fold_convert_loc (loc, etype, exp); + } + return fold_build2_loc (loc, GT_EXPR, type, exp, + build_int_cst (etype, 0)); + } + } + + /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low). + This requires wrap-around arithmetics for the type of the expression. */ + etype = range_check_type (etype); + if (etype == NULL_TREE) + return NULL_TREE; + + high = fold_convert_loc (loc, etype, high); + low = fold_convert_loc (loc, etype, low); + exp = fold_convert_loc (loc, etype, exp); + + value = const_binop (MINUS_EXPR, high, low); + + if (value != 0 && !TREE_OVERFLOW (value)) + return build_range_check (loc, type, + fold_build2_loc (loc, MINUS_EXPR, etype, exp, low), + 1, build_int_cst (etype, 0), value); + + return 0; +} + +/* Return the predecessor of VAL in its type, handling the infinite case. */ + +static tree +range_predecessor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (val, TYPE_MIN_VALUE (type), 0)) + return 0; + else + return range_binop (MINUS_EXPR, NULL_TREE, val, 0, + build_int_cst (TREE_TYPE (val), 1), 0); +} + +/* Return the successor of VAL in its type, handling the infinite case. */ + +static tree +range_successor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (val, TYPE_MAX_VALUE (type), 0)) + return 0; + else + return range_binop (PLUS_EXPR, NULL_TREE, val, 0, + build_int_cst (TREE_TYPE (val), 1), 0); +} + +/* Given two ranges, see if we can merge them into one. Return 1 if we + can, 0 if we can't. Set the output range into the specified parameters. */ + +bool +merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, + tree high0, int in1_p, tree low1, tree high1) +{ + int no_overlap; + int subset; + int temp; + tree tem; + int in_p; + tree low, high; + int lowequal = ((low0 == 0 && low1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + low0, 0, low1, 0))); + int highequal = ((high0 == 0 && high1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + high0, 1, high1, 1))); + + /* Make range 0 be the range that starts first, or ends last if they + start at the same value. Swap them if it isn't. */ + if (integer_onep (range_binop (GT_EXPR, integer_type_node, + low0, 0, low1, 0)) + || (lowequal + && integer_onep (range_binop (GT_EXPR, integer_type_node, + high1, 1, high0, 1)))) + { + temp = in0_p, in0_p = in1_p, in1_p = temp; + tem = low0, low0 = low1, low1 = tem; + tem = high0, high0 = high1, high1 = tem; + } + + /* If the second range is != high1 where high1 is the type maximum of + the type, try first merging with < high1 range. */ + if (low1 + && high1 + && TREE_CODE (low1) == INTEGER_CST + && (TREE_CODE (TREE_TYPE (low1)) == INTEGER_TYPE + || (TREE_CODE (TREE_TYPE (low1)) == ENUMERAL_TYPE + && known_eq (TYPE_PRECISION (TREE_TYPE (low1)), + GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (low1)))))) + && operand_equal_p (low1, high1, 0)) + { + if (tree_int_cst_equal (low1, TYPE_MAX_VALUE (TREE_TYPE (low1))) + && merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, + !in1_p, NULL_TREE, range_predecessor (low1))) + return true; + /* Similarly for the second range != low1 where low1 is the type minimum + of the type, try first merging with > low1 range. */ + if (tree_int_cst_equal (low1, TYPE_MIN_VALUE (TREE_TYPE (low1))) + && merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, + !in1_p, range_successor (low1), NULL_TREE)) + return true; + } + + /* Now flag two cases, whether the ranges are disjoint or whether the + second range is totally subsumed in the first. Note that the tests + below are simplified by the ones above. */ + no_overlap = integer_onep (range_binop (LT_EXPR, integer_type_node, + high0, 1, low1, 0)); + subset = integer_onep (range_binop (LE_EXPR, integer_type_node, + high1, 1, high0, 1)); + + /* We now have four cases, depending on whether we are including or + excluding the two ranges. */ + if (in0_p && in1_p) + { + /* If they don't overlap, the result is false. If the second range + is a subset it is the result. Otherwise, the range is from the start + of the second to the end of the first. */ + if (no_overlap) + in_p = 0, low = high = 0; + else if (subset) + in_p = 1, low = low1, high = high1; + else + in_p = 1, low = low1, high = high0; + } + + else if (in0_p && ! in1_p) + { + /* If they don't overlap, the result is the first range. If they are + equal, the result is false. If the second range is a subset of the + first, and the ranges begin at the same place, we go from just after + the end of the second range to the end of the first. If the second + range is not a subset of the first, or if it is a subset and both + ranges end at the same place, the range starts at the start of the + first range and ends just before the second range. + Otherwise, we can't describe this as a single range. */ + if (no_overlap) + in_p = 1, low = low0, high = high0; + else if (lowequal && highequal) + in_p = 0, low = high = 0; + else if (subset && lowequal) + { + low = range_successor (high1); + high = high0; + in_p = 1; + if (low == 0) + { + /* We are in the weird situation where high0 > high1 but + high1 has no successor. Punt. */ + return 0; + } + } + else if (! subset || highequal) + { + low = low0; + high = range_predecessor (low1); + in_p = 1; + if (high == 0) + { + /* low0 < low1 but low1 has no predecessor. Punt. */ + return 0; + } + } + else + return 0; + } + + else if (! in0_p && in1_p) + { + /* If they don't overlap, the result is the second range. If the second + is a subset of the first, the result is false. Otherwise, + the range starts just after the first range and ends at the + end of the second. */ + if (no_overlap) + in_p = 1, low = low1, high = high1; + else if (subset || highequal) + in_p = 0, low = high = 0; + else + { + low = range_successor (high0); + high = high1; + in_p = 1; + if (low == 0) + { + /* high1 > high0 but high0 has no successor. Punt. */ + return 0; + } + } + } + + else + { + /* The case where we are excluding both ranges. Here the complex case + is if they don't overlap. In that case, the only time we have a + range is if they are adjacent. If the second is a subset of the + first, the result is the first. Otherwise, the range to exclude + starts at the beginning of the first range and ends at the end of the + second. */ + if (no_overlap) + { + if (integer_onep (range_binop (EQ_EXPR, integer_type_node, + range_successor (high0), + 1, low1, 0))) + in_p = 0, low = low0, high = high1; + else + { + /* Canonicalize - [min, x] into - [-, x]. */ + if (low0 && TREE_CODE (low0) == INTEGER_CST) + switch (TREE_CODE (TREE_TYPE (low0))) + { + case ENUMERAL_TYPE: + if (maybe_ne (TYPE_PRECISION (TREE_TYPE (low0)), + GET_MODE_BITSIZE + (TYPE_MODE (TREE_TYPE (low0))))) + break; + /* FALLTHROUGH */ + case INTEGER_TYPE: + if (tree_int_cst_equal (low0, + TYPE_MIN_VALUE (TREE_TYPE (low0)))) + low0 = 0; + break; + case POINTER_TYPE: + if (TYPE_UNSIGNED (TREE_TYPE (low0)) + && integer_zerop (low0)) + low0 = 0; + break; + default: + break; + } + + /* Canonicalize - [x, max] into - [x, -]. */ + if (high1 && TREE_CODE (high1) == INTEGER_CST) + switch (TREE_CODE (TREE_TYPE (high1))) + { + case ENUMERAL_TYPE: + if (maybe_ne (TYPE_PRECISION (TREE_TYPE (high1)), + GET_MODE_BITSIZE + (TYPE_MODE (TREE_TYPE (high1))))) + break; + /* FALLTHROUGH */ + case INTEGER_TYPE: + if (tree_int_cst_equal (high1, + TYPE_MAX_VALUE (TREE_TYPE (high1)))) + high1 = 0; + break; + case POINTER_TYPE: + if (TYPE_UNSIGNED (TREE_TYPE (high1)) + && integer_zerop (range_binop (PLUS_EXPR, NULL_TREE, + high1, 1, + build_int_cst (TREE_TYPE (high1), 1), + 1))) + high1 = 0; + break; + default: + break; + } + + /* The ranges might be also adjacent between the maximum and + minimum values of the given type. For + - [{min,-}, x] and - [y, {max,-}] ranges where x + 1 < y + return + [x + 1, y - 1]. */ + if (low0 == 0 && high1 == 0) + { + low = range_successor (high0); + high = range_predecessor (low1); + if (low == 0 || high == 0) + return 0; + + in_p = 1; + } + else + return 0; + } + } + else if (subset) + in_p = 0, low = low0, high = high0; + else + in_p = 0, low = low0, high = high1; + } + + *pin_p = in_p, *plow = low, *phigh = high; + return 1; +} + + +/* Subroutine of fold, looking inside expressions of the form + A op B ? A : C, where (ARG00, COMP_CODE, ARG01), ARG1 and ARG2 + are the three operands of the COND_EXPR. This function is + being used also to optimize A op B ? C : A, by reversing the + comparison first. + + Return a folded expression whose code is not a COND_EXPR + anymore, or NULL_TREE if no folding opportunity is found. */ + +static tree +fold_cond_expr_with_comparison (location_t loc, tree type, + enum tree_code comp_code, + tree arg00, tree arg01, tree arg1, tree arg2) +{ + tree arg1_type = TREE_TYPE (arg1); + tree tem; + + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + + /* If we have A op 0 ? A : -A, consider applying the following + transformations: + + A == 0? A : -A same as -A + A != 0? A : -A same as A + A >= 0? A : -A same as abs (A) + A > 0? A : -A same as abs (A) + A <= 0? A : -A same as -abs (A) + A < 0? A : -A same as -abs (A) + + None of these transformations work for modes with signed + zeros. If A is +/-0, the first two transformations will + change the sign of the result (from +0 to -0, or vice + versa). The last four will fix the sign of the result, + even though the original expressions could be positive or + negative, depending on the sign of A. + + Note that all these transformations are correct if A is + NaN, since the two alternatives (A and -A) are also NaNs. */ + if (!HONOR_SIGNED_ZEROS (type) + && (FLOAT_TYPE_P (TREE_TYPE (arg01)) + ? real_zerop (arg01) + : integer_zerop (arg01)) + && ((TREE_CODE (arg2) == NEGATE_EXPR + && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0)) + /* In the case that A is of the form X-Y, '-A' (arg2) may + have already been folded to Y-X, check for that. */ + || (TREE_CODE (arg1) == MINUS_EXPR + && TREE_CODE (arg2) == MINUS_EXPR + && operand_equal_p (TREE_OPERAND (arg1, 0), + TREE_OPERAND (arg2, 1), 0) + && operand_equal_p (TREE_OPERAND (arg1, 1), + TREE_OPERAND (arg2, 0), 0)))) + switch (comp_code) + { + case EQ_EXPR: + case UNEQ_EXPR: + tem = fold_convert_loc (loc, arg1_type, arg1); + return fold_convert_loc (loc, type, negate_expr (tem)); + case NE_EXPR: + case LTGT_EXPR: + return fold_convert_loc (loc, type, arg1); + case UNGE_EXPR: + case UNGT_EXPR: + if (flag_trapping_math) + break; + /* Fall through. */ + case GE_EXPR: + case GT_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + break; + tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); + return fold_convert_loc (loc, type, tem); + case UNLE_EXPR: + case UNLT_EXPR: + if (flag_trapping_math) + break; + /* FALLTHRU */ + case LE_EXPR: + case LT_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + break; + if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) + { + /* A <= 0 ? A : -A for A INT_MIN is valid, but -abs(INT_MIN) + is not, invokes UB both in abs and in the negation of it. + So, use ABSU_EXPR instead. */ + tree utype = unsigned_type_for (TREE_TYPE (arg1)); + tem = fold_build1_loc (loc, ABSU_EXPR, utype, arg1); + tem = negate_expr (tem); + return fold_convert_loc (loc, type, tem); + } + else + { + tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); + return negate_expr (fold_convert_loc (loc, type, tem)); + } + default: + gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); + break; + } + + /* A != 0 ? A : 0 is simply A, unless A is -0. Likewise + A == 0 ? A : 0 is always 0 unless A is -0. Note that + both transformations are correct when A is NaN: A != 0 + is then true, and A == 0 is false. */ + + if (!HONOR_SIGNED_ZEROS (type) + && integer_zerop (arg01) && integer_zerop (arg2)) + { + if (comp_code == NE_EXPR) + return fold_convert_loc (loc, type, arg1); + else if (comp_code == EQ_EXPR) + return build_zero_cst (type); + } + + /* Try some transformations of A op B ? A : B. + + A == B? A : B same as B + A != B? A : B same as A + A >= B? A : B same as max (A, B) + A > B? A : B same as max (B, A) + A <= B? A : B same as min (A, B) + A < B? A : B same as min (B, A) + + As above, these transformations don't work in the presence + of signed zeros. For example, if A and B are zeros of + opposite sign, the first two transformations will change + the sign of the result. In the last four, the original + expressions give different results for (A=+0, B=-0) and + (A=-0, B=+0), but the transformed expressions do not. + + The first two transformations are correct if either A or B + is a NaN. In the first transformation, the condition will + be false, and B will indeed be chosen. In the case of the + second transformation, the condition A != B will be true, + and A will be chosen. + + The conversions to max() and min() are not correct if B is + a number and A is not. The conditions in the original + expressions will be false, so all four give B. The min() + and max() versions would give a NaN instead. */ + if (!HONOR_SIGNED_ZEROS (type) + && operand_equal_for_comparison_p (arg01, arg2) + /* Avoid these transformations if the COND_EXPR may be used + as an lvalue in the C++ front-end. PR c++/19199. */ + && (in_gimple_form + || VECTOR_TYPE_P (type) + || (! lang_GNU_CXX () + && strcmp (lang_hooks.name, "GNU Objective-C++") != 0) + || ! maybe_lvalue_p (arg1) + || ! maybe_lvalue_p (arg2))) + { + tree comp_op0 = arg00; + tree comp_op1 = arg01; + tree comp_type = TREE_TYPE (comp_op0); + + switch (comp_code) + { + case EQ_EXPR: + return fold_convert_loc (loc, type, arg2); + case NE_EXPR: + return fold_convert_loc (loc, type, arg1); + case LE_EXPR: + case LT_EXPR: + case UNLE_EXPR: + case UNLT_EXPR: + /* In C++ a ?: expression can be an lvalue, so put the + operand which will be used if they are equal first + so that we can convert this back to the + corresponding COND_EXPR. */ + if (!HONOR_NANS (arg1)) + { + comp_op0 = fold_convert_loc (loc, comp_type, comp_op0); + comp_op1 = fold_convert_loc (loc, comp_type, comp_op1); + tem = (comp_code == LE_EXPR || comp_code == UNLE_EXPR) + ? fold_build2_loc (loc, MIN_EXPR, comp_type, comp_op0, comp_op1) + : fold_build2_loc (loc, MIN_EXPR, comp_type, + comp_op1, comp_op0); + return fold_convert_loc (loc, type, tem); + } + break; + case GE_EXPR: + case GT_EXPR: + case UNGE_EXPR: + case UNGT_EXPR: + if (!HONOR_NANS (arg1)) + { + comp_op0 = fold_convert_loc (loc, comp_type, comp_op0); + comp_op1 = fold_convert_loc (loc, comp_type, comp_op1); + tem = (comp_code == GE_EXPR || comp_code == UNGE_EXPR) + ? fold_build2_loc (loc, MAX_EXPR, comp_type, comp_op0, comp_op1) + : fold_build2_loc (loc, MAX_EXPR, comp_type, + comp_op1, comp_op0); + return fold_convert_loc (loc, type, tem); + } + break; + case UNEQ_EXPR: + if (!HONOR_NANS (arg1)) + return fold_convert_loc (loc, type, arg2); + break; + case LTGT_EXPR: + if (!HONOR_NANS (arg1)) + return fold_convert_loc (loc, type, arg1); + break; + default: + gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); + break; + } + } + + return NULL_TREE; +} + + + +#ifndef LOGICAL_OP_NON_SHORT_CIRCUIT +#define LOGICAL_OP_NON_SHORT_CIRCUIT \ + (BRANCH_COST (optimize_function_for_speed_p (cfun), \ + false) >= 2) +#endif + +/* EXP is some logical combination of boolean tests. See if we can + merge it into some range test. Return the new tree if so. */ + +static tree +fold_range_test (location_t loc, enum tree_code code, tree type, + tree op0, tree op1) +{ + int or_op = (code == TRUTH_ORIF_EXPR + || code == TRUTH_OR_EXPR); + int in0_p, in1_p, in_p; + tree low0, low1, low, high0, high1, high; + bool strict_overflow_p = false; + tree tem, lhs, rhs; + const char * const warnmsg = G_("assuming signed overflow does not occur " + "when simplifying range test"); + + if (!INTEGRAL_TYPE_P (type)) + return 0; + + lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); + /* If op0 is known true or false and this is a short-circuiting + operation we must not merge with op1 since that makes side-effects + unconditional. So special-case this. */ + if (!lhs + && ((code == TRUTH_ORIF_EXPR && in0_p) + || (code == TRUTH_ANDIF_EXPR && !in0_p))) + return op0; + rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); + + /* If this is an OR operation, invert both sides; we will invert + again at the end. */ + if (or_op) + in0_p = ! in0_p, in1_p = ! in1_p; + + /* If both expressions are the same, if we can merge the ranges, and we + can build the range test, return it or it inverted. If one of the + ranges is always true or always false, consider it to be the same + expression as the other. */ + if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0)) + && merge_ranges (&in_p, &low, &high, in0_p, low0, high0, + in1_p, low1, high1) + && (tem = (build_range_check (loc, type, + lhs != 0 ? lhs + : rhs != 0 ? rhs : integer_zero_node, + in_p, low, high))) != 0) + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return or_op ? invert_truthvalue_loc (loc, tem) : tem; + } + + /* On machines where the branch cost is expensive, if this is a + short-circuited branch and the underlying object on both sides + is the same, make a non-short-circuit operation. */ + bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT; + if (param_logical_op_non_short_circuit != -1) + logical_op_non_short_circuit + = param_logical_op_non_short_circuit; + if (logical_op_non_short_circuit + && !sanitize_coverage_p () + && lhs != 0 && rhs != 0 + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR) + && operand_equal_p (lhs, rhs, 0)) + { + /* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR + unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in + which cases we can't do this. */ + if (simple_operand_p (lhs)) + return build2_loc (loc, code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, op0, op1); + + else if (!lang_hooks.decls.global_bindings_p () + && !CONTAINS_PLACEHOLDER_P (lhs)) + { + tree common = save_expr (lhs); + + if ((lhs = build_range_check (loc, type, common, + or_op ? ! in0_p : in0_p, + low0, high0)) != 0 + && (rhs = build_range_check (loc, type, common, + or_op ? ! in1_p : in1_p, + low1, high1)) != 0) + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, + WARN_STRICT_OVERFLOW_COMPARISON); + return build2_loc (loc, code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, lhs, rhs); + } + } + } + + return 0; +} + +/* Subroutine for fold_truth_andor_1: C is an INTEGER_CST interpreted as a P + bit value. Arrange things so the extra bits will be set to zero if and + only if C is signed-extended to its full width. If MASK is nonzero, + it is an INTEGER_CST that should be AND'ed with the extra bits. */ + +static tree +unextend (tree c, int p, int unsignedp, tree mask) +{ + tree type = TREE_TYPE (c); + int modesize = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type)); + tree temp; + + if (p == modesize || unsignedp) + return c; + + /* We work by getting just the sign bit into the low-order bit, then + into the high-order bit, then sign-extend. We then XOR that value + with C. */ + temp = build_int_cst (TREE_TYPE (c), + wi::extract_uhwi (wi::to_wide (c), p - 1, 1)); + + /* We must use a signed type in order to get an arithmetic right shift. + However, we must also avoid introducing accidental overflows, so that + a subsequent call to integer_zerop will work. Hence we must + do the type conversion here. At this point, the constant is either + zero or one, and the conversion to a signed type can never overflow. + We could get an overflow if this conversion is done anywhere else. */ + if (TYPE_UNSIGNED (type)) + temp = fold_convert (signed_type_for (type), temp); + + temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1)); + temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1)); + if (mask != 0) + temp = const_binop (BIT_AND_EXPR, temp, + fold_convert (TREE_TYPE (c), mask)); + /* If necessary, convert the type back to match the type of C. */ + if (TYPE_UNSIGNED (type)) + temp = fold_convert (type, temp); + + return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp)); +} + +/* For an expression that has the form + (A && B) || ~B + or + (A || B) && ~B, + we can drop one of the inner expressions and simplify to + A || ~B + or + A && ~B + LOC is the location of the resulting expression. OP is the inner + logical operation; the left-hand side in the examples above, while CMPOP + is the right-hand side. RHS_ONLY is used to prevent us from accidentally + removing a condition that guards another, as in + (A != NULL && A->...) || A == NULL + which we must not transform. If RHS_ONLY is true, only eliminate the + right-most operand of the inner logical operation. */ + +static tree +merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop, + bool rhs_only) +{ + tree type = TREE_TYPE (cmpop); + enum tree_code code = TREE_CODE (cmpop); + enum tree_code truthop_code = TREE_CODE (op); + tree lhs = TREE_OPERAND (op, 0); + tree rhs = TREE_OPERAND (op, 1); + tree orig_lhs = lhs, orig_rhs = rhs; + enum tree_code rhs_code = TREE_CODE (rhs); + enum tree_code lhs_code = TREE_CODE (lhs); + enum tree_code inv_code; + + if (TREE_SIDE_EFFECTS (op) || TREE_SIDE_EFFECTS (cmpop)) + return NULL_TREE; + + if (TREE_CODE_CLASS (code) != tcc_comparison) + return NULL_TREE; + + if (rhs_code == truthop_code) + { + tree newrhs = merge_truthop_with_opposite_arm (loc, rhs, cmpop, rhs_only); + if (newrhs != NULL_TREE) + { + rhs = newrhs; + rhs_code = TREE_CODE (rhs); + } + } + if (lhs_code == truthop_code && !rhs_only) + { + tree newlhs = merge_truthop_with_opposite_arm (loc, lhs, cmpop, false); + if (newlhs != NULL_TREE) + { + lhs = newlhs; + lhs_code = TREE_CODE (lhs); + } + } + + inv_code = invert_tree_comparison (code, HONOR_NANS (type)); + if (inv_code == rhs_code + && operand_equal_p (TREE_OPERAND (rhs, 0), TREE_OPERAND (cmpop, 0), 0) + && operand_equal_p (TREE_OPERAND (rhs, 1), TREE_OPERAND (cmpop, 1), 0)) + return lhs; + if (!rhs_only && inv_code == lhs_code + && operand_equal_p (TREE_OPERAND (lhs, 0), TREE_OPERAND (cmpop, 0), 0) + && operand_equal_p (TREE_OPERAND (lhs, 1), TREE_OPERAND (cmpop, 1), 0)) + return rhs; + if (rhs != orig_rhs || lhs != orig_lhs) + return fold_build2_loc (loc, truthop_code, TREE_TYPE (cmpop), + lhs, rhs); + return NULL_TREE; +} + +/* Find ways of folding logical expressions of LHS and RHS: + Try to merge two comparisons to the same innermost item. + Look for range tests like "ch >= '0' && ch <= '9'". + Look for combinations of simple terms on machines with expensive branches + and evaluate the RHS unconditionally. + + For example, if we have p->a == 2 && p->b == 4 and we can make an + object large enough to span both A and B, we can do this with a comparison + against the object ANDed with the a mask. + + If we have p->a == q->a && p->b == q->b, we may be able to use bit masking + operations to do this with one comparison. + + We check for both normal comparisons and the BIT_AND_EXPRs made this by + function and the one above. + + CODE is the logical operation being done. It can be TRUTH_ANDIF_EXPR, + TRUTH_AND_EXPR, TRUTH_ORIF_EXPR, or TRUTH_OR_EXPR. + + TRUTH_TYPE is the type of the logical operand and LHS and RHS are its + two operands. + + We return the simplified tree or 0 if no optimization is possible. */ + +static tree +fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type, + tree lhs, tree rhs) +{ + /* If this is the "or" of two comparisons, we can do something if + the comparisons are NE_EXPR. If this is the "and", we can do something + if the comparisons are EQ_EXPR. I.e., + (a->b == 2 && a->c == 4) can become (a->new == NEW). + + WANTED_CODE is this operation code. For single bit fields, we can + convert EQ_EXPR to NE_EXPR so we need not reject the "wrong" + comparison for one-bit fields. */ + + enum tree_code wanted_code; + enum tree_code lcode, rcode; + tree ll_arg, lr_arg, rl_arg, rr_arg; + tree ll_inner, lr_inner, rl_inner, rr_inner; + HOST_WIDE_INT ll_bitsize, ll_bitpos, lr_bitsize, lr_bitpos; + HOST_WIDE_INT rl_bitsize, rl_bitpos, rr_bitsize, rr_bitpos; + HOST_WIDE_INT xll_bitpos, xlr_bitpos, xrl_bitpos, xrr_bitpos; + HOST_WIDE_INT lnbitsize, lnbitpos, rnbitsize, rnbitpos; + int ll_unsignedp, lr_unsignedp, rl_unsignedp, rr_unsignedp; + int ll_reversep, lr_reversep, rl_reversep, rr_reversep; + machine_mode ll_mode, lr_mode, rl_mode, rr_mode; + scalar_int_mode lnmode, rnmode; + tree ll_mask, lr_mask, rl_mask, rr_mask; + tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask; + tree l_const, r_const; + tree lntype, rntype, result; + HOST_WIDE_INT first_bit, end_bit; + int volatilep; + + /* Start by getting the comparison codes. Fail if anything is volatile. + If one operand is a BIT_AND_EXPR with the constant one, treat it as if + it were surrounded with a NE_EXPR. */ + + if (TREE_SIDE_EFFECTS (lhs) || TREE_SIDE_EFFECTS (rhs)) + return 0; + + lcode = TREE_CODE (lhs); + rcode = TREE_CODE (rhs); + + if (lcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (lhs, 1))) + { + lhs = build2 (NE_EXPR, truth_type, lhs, + build_int_cst (TREE_TYPE (lhs), 0)); + lcode = NE_EXPR; + } + + if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1))) + { + rhs = build2 (NE_EXPR, truth_type, rhs, + build_int_cst (TREE_TYPE (rhs), 0)); + rcode = NE_EXPR; + } + + if (TREE_CODE_CLASS (lcode) != tcc_comparison + || TREE_CODE_CLASS (rcode) != tcc_comparison) + return 0; + + ll_arg = TREE_OPERAND (lhs, 0); + lr_arg = TREE_OPERAND (lhs, 1); + rl_arg = TREE_OPERAND (rhs, 0); + rr_arg = TREE_OPERAND (rhs, 1); + + /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations. */ + if (simple_operand_p (ll_arg) + && simple_operand_p (lr_arg)) + { + if (operand_equal_p (ll_arg, rl_arg, 0) + && operand_equal_p (lr_arg, rr_arg, 0)) + { + result = combine_comparisons (loc, code, lcode, rcode, + truth_type, ll_arg, lr_arg); + if (result) + return result; + } + else if (operand_equal_p (ll_arg, rr_arg, 0) + && operand_equal_p (lr_arg, rl_arg, 0)) + { + result = combine_comparisons (loc, code, lcode, + swap_tree_comparison (rcode), + truth_type, ll_arg, lr_arg); + if (result) + return result; + } + } + + code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); + + /* If the RHS can be evaluated unconditionally and its operands are + simple, it wins to evaluate the RHS unconditionally on machines + with expensive branches. In this case, this isn't a comparison + that can be merged. */ + + if (BRANCH_COST (optimize_function_for_speed_p (cfun), + false) >= 2 + && ! FLOAT_TYPE_P (TREE_TYPE (rl_arg)) + && simple_operand_p (rl_arg) + && simple_operand_p (rr_arg)) + { + /* Convert (a != 0) || (b != 0) into (a | b) != 0. */ + if (code == TRUTH_OR_EXPR + && lcode == NE_EXPR && integer_zerop (lr_arg) + && rcode == NE_EXPR && integer_zerop (rr_arg) + && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) + && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))) + return build2_loc (loc, NE_EXPR, truth_type, + build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), + ll_arg, rl_arg), + build_int_cst (TREE_TYPE (ll_arg), 0)); + + /* Convert (a == 0) && (b == 0) into (a | b) == 0. */ + if (code == TRUTH_AND_EXPR + && lcode == EQ_EXPR && integer_zerop (lr_arg) + && rcode == EQ_EXPR && integer_zerop (rr_arg) + && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) + && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))) + return build2_loc (loc, EQ_EXPR, truth_type, + build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), + ll_arg, rl_arg), + build_int_cst (TREE_TYPE (ll_arg), 0)); + } + + /* See if the comparisons can be merged. Then get all the parameters for + each side. */ + + if ((lcode != EQ_EXPR && lcode != NE_EXPR) + || (rcode != EQ_EXPR && rcode != NE_EXPR)) + return 0; + + ll_reversep = lr_reversep = rl_reversep = rr_reversep = 0; + volatilep = 0; + ll_inner = decode_field_reference (loc, &ll_arg, + &ll_bitsize, &ll_bitpos, &ll_mode, + &ll_unsignedp, &ll_reversep, &volatilep, + &ll_mask, &ll_and_mask); + lr_inner = decode_field_reference (loc, &lr_arg, + &lr_bitsize, &lr_bitpos, &lr_mode, + &lr_unsignedp, &lr_reversep, &volatilep, + &lr_mask, &lr_and_mask); + rl_inner = decode_field_reference (loc, &rl_arg, + &rl_bitsize, &rl_bitpos, &rl_mode, + &rl_unsignedp, &rl_reversep, &volatilep, + &rl_mask, &rl_and_mask); + rr_inner = decode_field_reference (loc, &rr_arg, + &rr_bitsize, &rr_bitpos, &rr_mode, + &rr_unsignedp, &rr_reversep, &volatilep, + &rr_mask, &rr_and_mask); + + /* It must be true that the inner operation on the lhs of each + comparison must be the same if we are to be able to do anything. + Then see if we have constants. If not, the same must be true for + the rhs's. */ + if (volatilep + || ll_reversep != rl_reversep + || ll_inner == 0 || rl_inner == 0 + || ! operand_equal_p (ll_inner, rl_inner, 0)) + return 0; + + if (TREE_CODE (lr_arg) == INTEGER_CST + && TREE_CODE (rr_arg) == INTEGER_CST) + { + l_const = lr_arg, r_const = rr_arg; + lr_reversep = ll_reversep; + } + else if (lr_reversep != rr_reversep + || lr_inner == 0 || rr_inner == 0 + || ! operand_equal_p (lr_inner, rr_inner, 0)) + return 0; + else + l_const = r_const = 0; + + /* If either comparison code is not correct for our logical operation, + fail. However, we can convert a one-bit comparison against zero into + the opposite comparison against that bit being set in the field. */ + + wanted_code = (code == TRUTH_AND_EXPR ? EQ_EXPR : NE_EXPR); + if (lcode != wanted_code) + { + if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask)) + { + /* Make the left operand unsigned, since we are only interested + in the value of one bit. Otherwise we are doing the wrong + thing below. */ + ll_unsignedp = 1; + l_const = ll_mask; + } + else + return 0; + } + + /* This is analogous to the code for l_const above. */ + if (rcode != wanted_code) + { + if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask)) + { + rl_unsignedp = 1; + r_const = rl_mask; + } + else + return 0; + } + + /* See if we can find a mode that contains both fields being compared on + the left. If we can't, fail. Otherwise, update all constants and masks + to be relative to a field of that size. */ + first_bit = MIN (ll_bitpos, rl_bitpos); + end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize); + if (!get_best_mode (end_bit - first_bit, first_bit, 0, 0, + TYPE_ALIGN (TREE_TYPE (ll_inner)), BITS_PER_WORD, + volatilep, &lnmode)) + return 0; + + lnbitsize = GET_MODE_BITSIZE (lnmode); + lnbitpos = first_bit & ~ (lnbitsize - 1); + lntype = lang_hooks.types.type_for_size (lnbitsize, 1); + xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos; + + if (ll_reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) + { + xll_bitpos = lnbitsize - xll_bitpos - ll_bitsize; + xrl_bitpos = lnbitsize - xrl_bitpos - rl_bitsize; + } + + ll_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, ll_mask), + size_int (xll_bitpos)); + rl_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, rl_mask), + size_int (xrl_bitpos)); + if (ll_mask == NULL_TREE || rl_mask == NULL_TREE) + return 0; + + if (l_const) + { + l_const = fold_convert_loc (loc, lntype, l_const); + l_const = unextend (l_const, ll_bitsize, ll_unsignedp, ll_and_mask); + l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos)); + if (l_const == NULL_TREE) + return 0; + if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const, + fold_build1_loc (loc, BIT_NOT_EXPR, + lntype, ll_mask)))) + { + warning (0, "comparison is always %d", wanted_code == NE_EXPR); + + return constant_boolean_node (wanted_code == NE_EXPR, truth_type); + } + } + if (r_const) + { + r_const = fold_convert_loc (loc, lntype, r_const); + r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask); + r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos)); + if (r_const == NULL_TREE) + return 0; + if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const, + fold_build1_loc (loc, BIT_NOT_EXPR, + lntype, rl_mask)))) + { + warning (0, "comparison is always %d", wanted_code == NE_EXPR); + + return constant_boolean_node (wanted_code == NE_EXPR, truth_type); + } + } + + /* If the right sides are not constant, do the same for it. Also, + disallow this optimization if a size, signedness or storage order + mismatch occurs between the left and right sides. */ + if (l_const == 0) + { + if (ll_bitsize != lr_bitsize || rl_bitsize != rr_bitsize + || ll_unsignedp != lr_unsignedp || rl_unsignedp != rr_unsignedp + || ll_reversep != lr_reversep + /* Make sure the two fields on the right + correspond to the left without being swapped. */ + || ll_bitpos - rl_bitpos != lr_bitpos - rr_bitpos) + return 0; + + first_bit = MIN (lr_bitpos, rr_bitpos); + end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize); + if (!get_best_mode (end_bit - first_bit, first_bit, 0, 0, + TYPE_ALIGN (TREE_TYPE (lr_inner)), BITS_PER_WORD, + volatilep, &rnmode)) + return 0; + + rnbitsize = GET_MODE_BITSIZE (rnmode); + rnbitpos = first_bit & ~ (rnbitsize - 1); + rntype = lang_hooks.types.type_for_size (rnbitsize, 1); + xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos; + + if (lr_reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) + { + xlr_bitpos = rnbitsize - xlr_bitpos - lr_bitsize; + xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize; + } + + lr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, + rntype, lr_mask), + size_int (xlr_bitpos)); + rr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, + rntype, rr_mask), + size_int (xrr_bitpos)); + if (lr_mask == NULL_TREE || rr_mask == NULL_TREE) + return 0; + + /* Make a mask that corresponds to both fields being compared. + Do this for both items being compared. If the operands are the + same size and the bits being compared are in the same position + then we can do this by masking both and comparing the masked + results. */ + ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); + lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask); + if (lnbitsize == rnbitsize + && xll_bitpos == xlr_bitpos + && lnbitpos >= 0 + && rnbitpos >= 0) + { + lhs = make_bit_field_ref (loc, ll_inner, ll_arg, + lntype, lnbitsize, lnbitpos, + ll_unsignedp || rl_unsignedp, ll_reversep); + if (! all_ones_mask_p (ll_mask, lnbitsize)) + lhs = build2 (BIT_AND_EXPR, lntype, lhs, ll_mask); + + rhs = make_bit_field_ref (loc, lr_inner, lr_arg, + rntype, rnbitsize, rnbitpos, + lr_unsignedp || rr_unsignedp, lr_reversep); + if (! all_ones_mask_p (lr_mask, rnbitsize)) + rhs = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask); + + return build2_loc (loc, wanted_code, truth_type, lhs, rhs); + } + + /* There is still another way we can do something: If both pairs of + fields being compared are adjacent, we may be able to make a wider + field containing them both. + + Note that we still must mask the lhs/rhs expressions. Furthermore, + the mask must be shifted to account for the shift done by + make_bit_field_ref. */ + if (((ll_bitsize + ll_bitpos == rl_bitpos + && lr_bitsize + lr_bitpos == rr_bitpos) + || (ll_bitpos == rl_bitpos + rl_bitsize + && lr_bitpos == rr_bitpos + rr_bitsize)) + && ll_bitpos >= 0 + && rl_bitpos >= 0 + && lr_bitpos >= 0 + && rr_bitpos >= 0) + { + tree type; + + lhs = make_bit_field_ref (loc, ll_inner, ll_arg, lntype, + ll_bitsize + rl_bitsize, + MIN (ll_bitpos, rl_bitpos), + ll_unsignedp, ll_reversep); + rhs = make_bit_field_ref (loc, lr_inner, lr_arg, rntype, + lr_bitsize + rr_bitsize, + MIN (lr_bitpos, rr_bitpos), + lr_unsignedp, lr_reversep); + + ll_mask = const_binop (RSHIFT_EXPR, ll_mask, + size_int (MIN (xll_bitpos, xrl_bitpos))); + lr_mask = const_binop (RSHIFT_EXPR, lr_mask, + size_int (MIN (xlr_bitpos, xrr_bitpos))); + if (ll_mask == NULL_TREE || lr_mask == NULL_TREE) + return 0; + + /* Convert to the smaller type before masking out unwanted bits. */ + type = lntype; + if (lntype != rntype) + { + if (lnbitsize > rnbitsize) + { + lhs = fold_convert_loc (loc, rntype, lhs); + ll_mask = fold_convert_loc (loc, rntype, ll_mask); + type = rntype; + } + else if (lnbitsize < rnbitsize) + { + rhs = fold_convert_loc (loc, lntype, rhs); + lr_mask = fold_convert_loc (loc, lntype, lr_mask); + type = lntype; + } + } + + if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize)) + lhs = build2 (BIT_AND_EXPR, type, lhs, ll_mask); + + if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize)) + rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask); + + return build2_loc (loc, wanted_code, truth_type, lhs, rhs); + } + + return 0; + } + + /* Handle the case of comparisons with constants. If there is something in + common between the masks, those bits of the constants must be the same. + If not, the condition is always false. Test for this to avoid generating + incorrect code below. */ + result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask); + if (! integer_zerop (result) + && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const), + const_binop (BIT_AND_EXPR, result, r_const)) != 1) + { + if (wanted_code == NE_EXPR) + { + warning (0, "%<or%> of unmatched not-equal tests is always 1"); + return constant_boolean_node (true, truth_type); + } + else + { + warning (0, "%<and%> of mutually exclusive equal-tests is always 0"); + return constant_boolean_node (false, truth_type); + } + } + + if (lnbitpos < 0) + return 0; + + /* Construct the expression we will return. First get the component + reference we will make. Unless the mask is all ones the width of + that field, perform the mask operation. Then compare with the + merged constant. */ + result = make_bit_field_ref (loc, ll_inner, ll_arg, + lntype, lnbitsize, lnbitpos, + ll_unsignedp || rl_unsignedp, ll_reversep); + + ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); + if (! all_ones_mask_p (ll_mask, lnbitsize)) + result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask); + + return build2_loc (loc, wanted_code, truth_type, result, + const_binop (BIT_IOR_EXPR, l_const, r_const)); +} + +/* T is an integer expression that is being multiplied, divided, or taken a + modulus (CODE says which and what kind of divide or modulus) by a + constant C. See if we can eliminate that operation by folding it with + other operations already in T. WIDE_TYPE, if non-null, is a type that + should be used for the computation if wider than our type. + + For example, if we are dividing (X * 8) + (Y * 16) by 4, we can return + (X * 2) + (Y * 4). We must, however, be assured that either the original + expression would not overflow or that overflow is undefined for the type + in the language in question. + + If we return a non-null expression, it is an equivalent form of the + original computation, but need not be in the original type. + + We set *STRICT_OVERFLOW_P to true if the return values depends on + signed overflow being undefined. Otherwise we do not change + *STRICT_OVERFLOW_P. */ + +static tree +extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) +{ + /* To avoid exponential search depth, refuse to allow recursion past + three levels. Beyond that (1) it's highly unlikely that we'll find + something interesting and (2) we've probably processed it before + when we built the inner expression. */ + + static int depth; + tree ret; + + if (depth > 3) + return NULL; + + depth++; + ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p); + depth--; + + return ret; +} + +static tree +extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) +{ + tree type = TREE_TYPE (t); + enum tree_code tcode = TREE_CODE (t); + tree ctype = (wide_type != 0 + && (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type)) + > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type))) + ? wide_type : type); + tree t1, t2; + int same_p = tcode == code; + tree op0 = NULL_TREE, op1 = NULL_TREE; + bool sub_strict_overflow_p; + + /* Don't deal with constants of zero here; they confuse the code below. */ + if (integer_zerop (c)) + return NULL_TREE; + + if (TREE_CODE_CLASS (tcode) == tcc_unary) + op0 = TREE_OPERAND (t, 0); + + if (TREE_CODE_CLASS (tcode) == tcc_binary) + op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1); + + /* Note that we need not handle conditional operations here since fold + already handles those cases. So just do arithmetic here. */ + switch (tcode) + { + case INTEGER_CST: + /* For a constant, we can always simplify if we are a multiply + or (for divide and modulus) if it is a multiple of our constant. */ + if (code == MULT_EXPR + || wi::multiple_of_p (wi::to_wide (t), wi::to_wide (c), + TYPE_SIGN (type))) + { + tree tem = const_binop (code, fold_convert (ctype, t), + fold_convert (ctype, c)); + /* If the multiplication overflowed, we lost information on it. + See PR68142 and PR69845. */ + if (TREE_OVERFLOW (tem)) + return NULL_TREE; + return tem; + } + break; + + CASE_CONVERT: case NON_LVALUE_EXPR: + if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))) + break; + /* If op0 is an expression ... */ + if ((COMPARISON_CLASS_P (op0) + || UNARY_CLASS_P (op0) + || BINARY_CLASS_P (op0) + || VL_EXP_CLASS_P (op0) + || EXPRESSION_CLASS_P (op0)) + /* ... and has wrapping overflow, and its type is smaller + than ctype, then we cannot pass through as widening. */ + && ((TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0)) + && (TYPE_PRECISION (ctype) + > TYPE_PRECISION (TREE_TYPE (op0)))) + /* ... or this is a truncation (t is narrower than op0), + then we cannot pass through this narrowing. */ + || (TYPE_PRECISION (type) + < TYPE_PRECISION (TREE_TYPE (op0))) + /* ... or signedness changes for division or modulus, + then we cannot pass through this conversion. */ + || (code != MULT_EXPR + && (TYPE_UNSIGNED (ctype) + != TYPE_UNSIGNED (TREE_TYPE (op0)))) + /* ... or has undefined overflow while the converted to + type has not, we cannot do the operation in the inner type + as that would introduce undefined overflow. */ + || (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)) + && !TYPE_OVERFLOW_UNDEFINED (type)))) + break; + + /* Pass the constant down and see if we can make a simplification. If + we can, replace this expression with the inner simplification for + possible later conversion to our or some other type. */ + if ((t2 = fold_convert (TREE_TYPE (op0), c)) != 0 + && TREE_CODE (t2) == INTEGER_CST + && !TREE_OVERFLOW (t2) + && (t1 = extract_muldiv (op0, t2, code, + code == MULT_EXPR ? ctype : NULL_TREE, + strict_overflow_p)) != 0) + return t1; + break; + + case ABS_EXPR: + /* If widening the type changes it from signed to unsigned, then we + must avoid building ABS_EXPR itself as unsigned. */ + if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type)) + { + tree cstype = (*signed_type_for) (ctype); + if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p)) + != 0) + { + t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1)); + return fold_convert (ctype, t1); + } + break; + } + /* If the constant is negative, we cannot simplify this. */ + if (tree_int_cst_sgn (c) == -1) + break; + /* FALLTHROUGH */ + case NEGATE_EXPR: + /* For division and modulus, type can't be unsigned, as e.g. + (-(x / 2U)) / 2U isn't equal to -((x / 2U) / 2U) for x >= 2. + For signed types, even with wrapping overflow, this is fine. */ + if (code != MULT_EXPR && TYPE_UNSIGNED (type)) + break; + if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p)) + != 0) + return fold_build1 (tcode, ctype, fold_convert (ctype, t1)); + break; + + case MIN_EXPR: case MAX_EXPR: + /* If widening the type changes the signedness, then we can't perform + this optimization as that changes the result. */ + if (TYPE_UNSIGNED (ctype) != TYPE_UNSIGNED (type)) + break; + + /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ + sub_strict_overflow_p = false; + if ((t1 = extract_muldiv (op0, c, code, wide_type, + &sub_strict_overflow_p)) != 0 + && (t2 = extract_muldiv (op1, c, code, wide_type, + &sub_strict_overflow_p)) != 0) + { + if (tree_int_cst_sgn (c) < 0) + tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR); + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } + break; + + case LSHIFT_EXPR: case RSHIFT_EXPR: + /* If the second operand is constant, this is a multiplication + or floor division, by a power of two, so we can treat it that + way unless the multiplier or divisor overflows. Signed + left-shift overflow is implementation-defined rather than + undefined in C90, so do not convert signed left shift into + multiplication. */ + if (TREE_CODE (op1) == INTEGER_CST + && (tcode == RSHIFT_EXPR || TYPE_UNSIGNED (TREE_TYPE (op0))) + /* const_binop may not detect overflow correctly, + so check for it explicitly here. */ + && wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), + wi::to_wide (op1)) + && (t1 = fold_convert (ctype, + const_binop (LSHIFT_EXPR, size_one_node, + op1))) != 0 + && !TREE_OVERFLOW (t1)) + return extract_muldiv (build2 (tcode == LSHIFT_EXPR + ? MULT_EXPR : FLOOR_DIV_EXPR, + ctype, + fold_convert (ctype, op0), + t1), + c, code, wide_type, strict_overflow_p); + break; + + case PLUS_EXPR: case MINUS_EXPR: + /* See if we can eliminate the operation on both sides. If we can, we + can return a new PLUS or MINUS. If we can't, the only remaining + cases where we can do anything are if the second operand is a + constant. */ + sub_strict_overflow_p = false; + t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p); + t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p); + if (t1 != 0 && t2 != 0 + && TYPE_OVERFLOW_WRAPS (ctype) + && (code == MULT_EXPR + /* If not multiplication, we can only do this if both operands + are divisible by c. */ + || (multiple_of_p (ctype, op0, c) + && multiple_of_p (ctype, op1, c)))) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } + + /* If this was a subtraction, negate OP1 and set it to be an addition. + This simplifies the logic below. */ + if (tcode == MINUS_EXPR) + { + tcode = PLUS_EXPR, op1 = negate_expr (op1); + /* If OP1 was not easily negatable, the constant may be OP0. */ + if (TREE_CODE (op0) == INTEGER_CST) + { + std::swap (op0, op1); + std::swap (t1, t2); + } + } + + if (TREE_CODE (op1) != INTEGER_CST) + break; + + /* If either OP1 or C are negative, this optimization is not safe for + some of the division and remainder types while for others we need + to change the code. */ + if (tree_int_cst_sgn (op1) < 0 || tree_int_cst_sgn (c) < 0) + { + if (code == CEIL_DIV_EXPR) + code = FLOOR_DIV_EXPR; + else if (code == FLOOR_DIV_EXPR) + code = CEIL_DIV_EXPR; + else if (code != MULT_EXPR + && code != CEIL_MOD_EXPR && code != FLOOR_MOD_EXPR) + break; + } + + /* If it's a multiply or a division/modulus operation of a multiple + of our constant, do the operation and verify it doesn't overflow. */ + if (code == MULT_EXPR + || wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), + TYPE_SIGN (type))) + { + op1 = const_binop (code, fold_convert (ctype, op1), + fold_convert (ctype, c)); + /* We allow the constant to overflow with wrapping semantics. */ + if (op1 == 0 + || (TREE_OVERFLOW (op1) && !TYPE_OVERFLOW_WRAPS (ctype))) + break; + } + else + break; + + /* If we have an unsigned type, we cannot widen the operation since it + will change the result if the original computation overflowed. */ + if (TYPE_UNSIGNED (ctype) && ctype != type) + break; + + /* The last case is if we are a multiply. In that case, we can + apply the distributive law to commute the multiply and addition + if the multiplication of the constants doesn't overflow + and overflow is defined. With undefined overflow + op0 * c might overflow, while (op0 + orig_op1) * c doesn't. + But fold_plusminus_mult_expr would factor back any power-of-two + value so do not distribute in the first place in this case. */ + if (code == MULT_EXPR + && TYPE_OVERFLOW_WRAPS (ctype) + && !(tree_fits_shwi_p (c) && pow2p_hwi (absu_hwi (tree_to_shwi (c))))) + return fold_build2 (tcode, ctype, + fold_build2 (code, ctype, + fold_convert (ctype, op0), + fold_convert (ctype, c)), + op1); + + break; + + case MULT_EXPR: + /* We have a special case here if we are doing something like + (C * 8) % 4 since we know that's zero. */ + if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR + || code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR) + /* If the multiplication can overflow we cannot optimize this. */ + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)) + && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), + TYPE_SIGN (type))) + { + *strict_overflow_p = true; + return omit_one_operand (type, integer_zero_node, op0); + } + + /* ... fall through ... */ + + case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: + /* If we can extract our operation from the LHS, do so and return a + new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, + do something only if the second operand is a constant. */ + if (same_p + && TYPE_OVERFLOW_WRAPS (ctype) + && (t1 = extract_muldiv (op0, c, code, wide_type, + strict_overflow_p)) != 0) + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, op1)); + else if (tcode == MULT_EXPR && code == MULT_EXPR + && TYPE_OVERFLOW_WRAPS (ctype) + && (t1 = extract_muldiv (op1, c, code, wide_type, + strict_overflow_p)) != 0) + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, t1)); + else if (TREE_CODE (op1) != INTEGER_CST) + return 0; + + /* If these are the same operation types, we can associate them + assuming no overflow. */ + if (tcode == code) + { + bool overflow_p = false; + wi::overflow_type overflow_mul; + signop sign = TYPE_SIGN (ctype); + unsigned prec = TYPE_PRECISION (ctype); + wide_int mul = wi::mul (wi::to_wide (op1, prec), + wi::to_wide (c, prec), + sign, &overflow_mul); + overflow_p = TREE_OVERFLOW (c) | TREE_OVERFLOW (op1); + if (overflow_mul + && ((sign == UNSIGNED && tcode != MULT_EXPR) || sign == SIGNED)) + overflow_p = true; + if (!overflow_p) + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + wide_int_to_tree (ctype, mul)); + } + + /* If these operations "cancel" each other, we have the main + optimizations of this pass, which occur when either constant is a + multiple of the other, in which case we replace this with either an + operation or CODE or TCODE. + + If we have an unsigned type, we cannot do this since it will change + the result if the original computation overflowed. */ + if (TYPE_OVERFLOW_UNDEFINED (ctype) + && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR) + || (tcode == MULT_EXPR + && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR + && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR + && code != MULT_EXPR))) + { + if (wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), + TYPE_SIGN (type))) + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + op1, c))); + } + else if (wi::multiple_of_p (wi::to_wide (c), wi::to_wide (op1), + TYPE_SIGN (type))) + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (code, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + c, op1))); + } + } + break; + + default: + break; + } + + return 0; +} + +/* Return a node which has the indicated constant VALUE (either 0 or + 1 for scalars or {-1,-1,..} or {0,0,...} for vectors), + and is of the indicated TYPE. */ + +tree +constant_boolean_node (bool value, tree type) +{ + if (type == integer_type_node) + return value ? integer_one_node : integer_zero_node; + else if (type == boolean_type_node) + return value ? boolean_true_node : boolean_false_node; + else if (TREE_CODE (type) == VECTOR_TYPE) + return build_vector_from_val (type, + build_int_cst (TREE_TYPE (type), + value ? -1 : 0)); + else + return fold_convert (type, value ? integer_one_node : integer_zero_node); +} + + +/* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'. + Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here + CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)' + expression, and ARG to `a'. If COND_FIRST_P is nonzero, then the + COND is the first argument to CODE; otherwise (as in the example + given here), it is the second argument. TYPE is the type of the + original expression. Return NULL_TREE if no simplification is + possible. */ + +static tree +fold_binary_op_with_conditional_arg (location_t loc, + enum tree_code code, + tree type, tree op0, tree op1, + tree cond, tree arg, int cond_first_p) +{ + tree cond_type = cond_first_p ? TREE_TYPE (op0) : TREE_TYPE (op1); + tree arg_type = cond_first_p ? TREE_TYPE (op1) : TREE_TYPE (op0); + tree test, true_value, false_value; + tree lhs = NULL_TREE; + tree rhs = NULL_TREE; + enum tree_code cond_code = COND_EXPR; + + /* Do not move possibly trapping operations into the conditional as this + pessimizes code and causes gimplification issues when applied late. */ + if (operation_could_trap_p (code, FLOAT_TYPE_P (type), + ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_TRAPS (type), op1)) + return NULL_TREE; + + if (TREE_CODE (cond) == COND_EXPR + || TREE_CODE (cond) == VEC_COND_EXPR) + { + test = TREE_OPERAND (cond, 0); + true_value = TREE_OPERAND (cond, 1); + false_value = TREE_OPERAND (cond, 2); + /* If this operand throws an expression, then it does not make + sense to try to perform a logical or arithmetic operation + involving it. */ + if (VOID_TYPE_P (TREE_TYPE (true_value))) + lhs = true_value; + if (VOID_TYPE_P (TREE_TYPE (false_value))) + rhs = false_value; + } + else if (!(TREE_CODE (type) != VECTOR_TYPE + && TREE_CODE (TREE_TYPE (cond)) == VECTOR_TYPE)) + { + tree testtype = TREE_TYPE (cond); + test = cond; + true_value = constant_boolean_node (true, testtype); + false_value = constant_boolean_node (false, testtype); + } + else + /* Detect the case of mixing vector and scalar types - bail out. */ + return NULL_TREE; + + if (TREE_CODE (TREE_TYPE (test)) == VECTOR_TYPE) + cond_code = VEC_COND_EXPR; + + /* This transformation is only worthwhile if we don't have to wrap ARG + in a SAVE_EXPR and the operation can be simplified without recursing + on at least one of the branches once its pushed inside the COND_EXPR. */ + if (!TREE_CONSTANT (arg) + && (TREE_SIDE_EFFECTS (arg) + || TREE_CODE (arg) == COND_EXPR || TREE_CODE (arg) == VEC_COND_EXPR + || TREE_CONSTANT (true_value) || TREE_CONSTANT (false_value))) + return NULL_TREE; + + arg = fold_convert_loc (loc, arg_type, arg); + if (lhs == 0) + { + true_value = fold_convert_loc (loc, cond_type, true_value); + if (cond_first_p) + lhs = fold_build2_loc (loc, code, type, true_value, arg); + else + lhs = fold_build2_loc (loc, code, type, arg, true_value); + } + if (rhs == 0) + { + false_value = fold_convert_loc (loc, cond_type, false_value); + if (cond_first_p) + rhs = fold_build2_loc (loc, code, type, false_value, arg); + else + rhs = fold_build2_loc (loc, code, type, arg, false_value); + } + + /* Check that we have simplified at least one of the branches. */ + if (!TREE_CONSTANT (arg) && !TREE_CONSTANT (lhs) && !TREE_CONSTANT (rhs)) + return NULL_TREE; + + return fold_build3_loc (loc, cond_code, type, test, lhs, rhs); +} + + +/* Subroutine of fold() that checks for the addition of ARG +/- 0.0. + + If !NEGATE, return true if ZERO_ARG is +/-0.0 and, for all ARG of + type TYPE, ARG + ZERO_ARG is the same as ARG. If NEGATE, return true + if ARG - ZERO_ARG is the same as X. + + If ARG is NULL, check for any value of type TYPE. + + X + 0 and X - 0 both give X when X is NaN, infinite, or nonzero + and finite. The problematic cases are when X is zero, and its mode + has signed zeros. In the case of rounding towards -infinity, + X - 0 is not the same as X because 0 - 0 is -0. In other rounding + modes, X + 0 is not the same as X because -0 + 0 is 0. */ + +bool +fold_real_zero_addition_p (const_tree type, const_tree arg, + const_tree zero_arg, int negate) +{ + if (!real_zerop (zero_arg)) + return false; + + /* Don't allow the fold with -fsignaling-nans. */ + if (arg ? tree_expr_maybe_signaling_nan_p (arg) : HONOR_SNANS (type)) + return false; + + /* Allow the fold if zeros aren't signed, or their sign isn't important. */ + if (!HONOR_SIGNED_ZEROS (type)) + return true; + + /* There is no case that is safe for all rounding modes. */ + if (HONOR_SIGN_DEPENDENT_ROUNDING (type)) + return false; + + /* In a vector or complex, we would need to check the sign of all zeros. */ + if (TREE_CODE (zero_arg) == VECTOR_CST) + zero_arg = uniform_vector_p (zero_arg); + if (!zero_arg || TREE_CODE (zero_arg) != REAL_CST) + return false; + + /* Treat x + -0 as x - 0 and x - -0 as x + 0. */ + if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (zero_arg))) + negate = !negate; + + /* The mode has signed zeros, and we have to honor their sign. + In this situation, there are only two cases we can return true for. + (i) X - 0 is the same as X with default rounding. + (ii) X + 0 is X when X can't possibly be -0.0. */ + return negate || (arg && !tree_expr_maybe_real_minus_zero_p (arg)); +} + +/* Subroutine of match.pd that optimizes comparisons of a division by + a nonzero integer constant against an integer constant, i.e. + X/C1 op C2. + + CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, + GE_EXPR or LE_EXPR. ARG01 and ARG1 must be a INTEGER_CST. */ + +enum tree_code +fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo, + tree *hi, bool *neg_overflow) +{ + tree prod, tmp, type = TREE_TYPE (c1); + signop sign = TYPE_SIGN (type); + wi::overflow_type overflow; + + /* We have to do this the hard way to detect unsigned overflow. + prod = int_const_binop (MULT_EXPR, c1, c2); */ + wide_int val = wi::mul (wi::to_wide (c1), wi::to_wide (c2), sign, &overflow); + prod = force_fit_type (type, val, -1, overflow); + *neg_overflow = false; + + if (sign == UNSIGNED) + { + tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); + *lo = prod; + + /* Likewise *hi = int_const_binop (PLUS_EXPR, prod, tmp). */ + val = wi::add (wi::to_wide (prod), wi::to_wide (tmp), sign, &overflow); + *hi = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (prod)); + } + else if (tree_int_cst_sgn (c1) >= 0) + { + tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); + switch (tree_int_cst_sgn (c2)) + { + case -1: + *neg_overflow = true; + *lo = int_const_binop (MINUS_EXPR, prod, tmp); + *hi = prod; + break; + + case 0: + *lo = fold_negate_const (tmp, type); + *hi = tmp; + break; + + case 1: + *hi = int_const_binop (PLUS_EXPR, prod, tmp); + *lo = prod; + break; + + default: + gcc_unreachable (); + } + } + else + { + /* A negative divisor reverses the relational operators. */ + code = swap_tree_comparison (code); + + tmp = int_const_binop (PLUS_EXPR, c1, build_int_cst (type, 1)); + switch (tree_int_cst_sgn (c2)) + { + case -1: + *hi = int_const_binop (MINUS_EXPR, prod, tmp); + *lo = prod; + break; + + case 0: + *hi = fold_negate_const (tmp, type); + *lo = tmp; + break; + + case 1: + *neg_overflow = true; + *lo = int_const_binop (PLUS_EXPR, prod, tmp); + *hi = prod; + break; + + default: + gcc_unreachable (); + } + } + + if (code != EQ_EXPR && code != NE_EXPR) + return code; + + if (TREE_OVERFLOW (*lo) + || operand_equal_p (*lo, TYPE_MIN_VALUE (type), 0)) + *lo = NULL_TREE; + if (TREE_OVERFLOW (*hi) + || operand_equal_p (*hi, TYPE_MAX_VALUE (type), 0)) + *hi = NULL_TREE; + + return code; +} + + +/* If CODE with arguments ARG0 and ARG1 represents a single bit + equality/inequality test, then return a simplified form of the test + using a sign testing. Otherwise return NULL. TYPE is the desired + result type. */ + +static tree +fold_single_bit_test_into_sign_test (location_t loc, + enum tree_code code, tree arg0, tree arg1, + tree result_type) +{ + /* If this is testing a single bit, we can optimize the test. */ + if ((code == NE_EXPR || code == EQ_EXPR) + && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + /* If we have (A & C) != 0 where C is the sign bit of A, convert + this into A < 0. Similarly for (A & C) == 0 into A >= 0. */ + tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)); + + if (arg00 != NULL_TREE + /* This is only a win if casting to a signed type is cheap, + i.e. when arg00's type is not a partial mode. */ + && type_has_mode_precision_p (TREE_TYPE (arg00))) + { + tree stype = signed_type_for (TREE_TYPE (arg00)); + return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR : LT_EXPR, + result_type, + fold_convert_loc (loc, stype, arg00), + build_int_cst (stype, 0)); + } + } + + return NULL_TREE; +} + +/* If CODE with arguments ARG0 and ARG1 represents a single bit + equality/inequality test, then return a simplified form of + the test using shifts and logical operations. Otherwise return + NULL. TYPE is the desired result type. */ + +tree +fold_single_bit_test (location_t loc, enum tree_code code, + tree arg0, tree arg1, tree result_type) +{ + /* If this is testing a single bit, we can optimize the test. */ + if ((code == NE_EXPR || code == EQ_EXPR) + && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tree inner = TREE_OPERAND (arg0, 0); + tree type = TREE_TYPE (arg0); + int bitnum = tree_log2 (TREE_OPERAND (arg0, 1)); + scalar_int_mode operand_mode = SCALAR_INT_TYPE_MODE (type); + int ops_unsigned; + tree signed_type, unsigned_type, intermediate_type; + tree tem, one; + + /* First, see if we can fold the single bit test into a sign-bit + test. */ + tem = fold_single_bit_test_into_sign_test (loc, code, arg0, arg1, + result_type); + if (tem) + return tem; + + /* Otherwise we have (A & C) != 0 where C is a single bit, + convert that into ((A >> C2) & 1). Where C2 = log2(C). + Similarly for (A & C) == 0. */ + + /* If INNER is a right shift of a constant and it plus BITNUM does + not overflow, adjust BITNUM and INNER. */ + if (TREE_CODE (inner) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST + && bitnum < TYPE_PRECISION (type) + && wi::ltu_p (wi::to_wide (TREE_OPERAND (inner, 1)), + TYPE_PRECISION (type) - bitnum)) + { + bitnum += tree_to_uhwi (TREE_OPERAND (inner, 1)); + inner = TREE_OPERAND (inner, 0); + } + + /* If we are going to be able to omit the AND below, we must do our + operations as unsigned. If we must use the AND, we have a choice. + Normally unsigned is faster, but for some machines signed is. */ + ops_unsigned = (load_extend_op (operand_mode) == SIGN_EXTEND + && !flag_syntax_only) ? 0 : 1; + + signed_type = lang_hooks.types.type_for_mode (operand_mode, 0); + unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1); + intermediate_type = ops_unsigned ? unsigned_type : signed_type; + inner = fold_convert_loc (loc, intermediate_type, inner); + + if (bitnum != 0) + inner = build2 (RSHIFT_EXPR, intermediate_type, + inner, size_int (bitnum)); + + one = build_int_cst (intermediate_type, 1); + + if (code == EQ_EXPR) + inner = fold_build2_loc (loc, BIT_XOR_EXPR, intermediate_type, inner, one); + + /* Put the AND last so it can combine with more things. */ + inner = build2 (BIT_AND_EXPR, intermediate_type, inner, one); + + /* Make sure to return the proper type. */ + inner = fold_convert_loc (loc, result_type, inner); + + return inner; + } + return NULL_TREE; +} + +/* Test whether it is preferable to swap two operands, ARG0 and + ARG1, for example because ARG0 is an integer constant and ARG1 + isn't. */ + +bool +tree_swap_operands_p (const_tree arg0, const_tree arg1) +{ + if (CONSTANT_CLASS_P (arg1)) + return 0; + if (CONSTANT_CLASS_P (arg0)) + return 1; + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CONSTANT (arg1)) + return 0; + if (TREE_CONSTANT (arg0)) + return 1; + + /* It is preferable to swap two SSA_NAME to ensure a canonical form + for commutative and comparison operators. Ensuring a canonical + form allows the optimizers to find additional redundancies without + having to explicitly check for both orderings. */ + if (TREE_CODE (arg0) == SSA_NAME + && TREE_CODE (arg1) == SSA_NAME + && SSA_NAME_VERSION (arg0) > SSA_NAME_VERSION (arg1)) + return 1; + + /* Put SSA_NAMEs last. */ + if (TREE_CODE (arg1) == SSA_NAME) + return 0; + if (TREE_CODE (arg0) == SSA_NAME) + return 1; + + /* Put variables last. */ + if (DECL_P (arg1)) + return 0; + if (DECL_P (arg0)) + return 1; + + return 0; +} + + +/* Fold A < X && A + 1 > Y to A < X && A >= Y. Normally A + 1 > Y + means A >= Y && A != MAX, but in this case we know that + A < X <= MAX. INEQ is A + 1 > Y, BOUND is A < X. */ + +static tree +fold_to_nonsharp_ineq_using_bound (location_t loc, tree ineq, tree bound) +{ + tree a, typea, type = TREE_TYPE (ineq), a1, diff, y; + + if (TREE_CODE (bound) == LT_EXPR) + a = TREE_OPERAND (bound, 0); + else if (TREE_CODE (bound) == GT_EXPR) + a = TREE_OPERAND (bound, 1); + else + return NULL_TREE; + + typea = TREE_TYPE (a); + if (!INTEGRAL_TYPE_P (typea) + && !POINTER_TYPE_P (typea)) + return NULL_TREE; + + if (TREE_CODE (ineq) == LT_EXPR) + { + a1 = TREE_OPERAND (ineq, 1); + y = TREE_OPERAND (ineq, 0); + } + else if (TREE_CODE (ineq) == GT_EXPR) + { + a1 = TREE_OPERAND (ineq, 0); + y = TREE_OPERAND (ineq, 1); + } + else + return NULL_TREE; + + if (TREE_TYPE (a1) != typea) + return NULL_TREE; + + if (POINTER_TYPE_P (typea)) + { + /* Convert the pointer types into integer before taking the difference. */ + tree ta = fold_convert_loc (loc, ssizetype, a); + tree ta1 = fold_convert_loc (loc, ssizetype, a1); + diff = fold_binary_loc (loc, MINUS_EXPR, ssizetype, ta1, ta); + } + else + diff = fold_binary_loc (loc, MINUS_EXPR, typea, a1, a); + + if (!diff || !integer_onep (diff)) + return NULL_TREE; + + return fold_build2_loc (loc, GE_EXPR, type, a, y); +} + +/* Fold a sum or difference of at least one multiplication. + Returns the folded tree or NULL if no simplification could be made. */ + +static tree +fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type, + tree arg0, tree arg1) +{ + tree arg00, arg01, arg10, arg11; + tree alt0 = NULL_TREE, alt1 = NULL_TREE, same; + + /* (A * C) +- (B * C) -> (A+-B) * C. + (A * C) +- A -> A * (C+-1). + We are most concerned about the case where C is a constant, + but other combinations show up during loop reduction. Since + it is not difficult, try all four possibilities. */ + + if (TREE_CODE (arg0) == MULT_EXPR) + { + arg00 = TREE_OPERAND (arg0, 0); + arg01 = TREE_OPERAND (arg0, 1); + } + else if (TREE_CODE (arg0) == INTEGER_CST) + { + arg00 = build_one_cst (type); + arg01 = arg0; + } + else + { + /* We cannot generate constant 1 for fract. */ + if (ALL_FRACT_MODE_P (TYPE_MODE (type))) + return NULL_TREE; + arg00 = arg0; + arg01 = build_one_cst (type); + } + if (TREE_CODE (arg1) == MULT_EXPR) + { + arg10 = TREE_OPERAND (arg1, 0); + arg11 = TREE_OPERAND (arg1, 1); + } + else if (TREE_CODE (arg1) == INTEGER_CST) + { + arg10 = build_one_cst (type); + /* As we canonicalize A - 2 to A + -2 get rid of that sign for + the purpose of this canonicalization. */ + if (wi::neg_p (wi::to_wide (arg1), TYPE_SIGN (TREE_TYPE (arg1))) + && negate_expr_p (arg1) + && code == PLUS_EXPR) + { + arg11 = negate_expr (arg1); + code = MINUS_EXPR; + } + else + arg11 = arg1; + } + else + { + /* We cannot generate constant 1 for fract. */ + if (ALL_FRACT_MODE_P (TYPE_MODE (type))) + return NULL_TREE; + arg10 = arg1; + arg11 = build_one_cst (type); + } + same = NULL_TREE; + + /* Prefer factoring a common non-constant. */ + if (operand_equal_p (arg00, arg10, 0)) + same = arg00, alt0 = arg01, alt1 = arg11; + else if (operand_equal_p (arg01, arg11, 0)) + same = arg01, alt0 = arg00, alt1 = arg10; + else if (operand_equal_p (arg00, arg11, 0)) + same = arg00, alt0 = arg01, alt1 = arg10; + else if (operand_equal_p (arg01, arg10, 0)) + same = arg01, alt0 = arg00, alt1 = arg11; + + /* No identical multiplicands; see if we can find a common + power-of-two factor in non-power-of-two multiplies. This + can help in multi-dimensional array access. */ + else if (tree_fits_shwi_p (arg01) && tree_fits_shwi_p (arg11)) + { + HOST_WIDE_INT int01 = tree_to_shwi (arg01); + HOST_WIDE_INT int11 = tree_to_shwi (arg11); + HOST_WIDE_INT tmp; + bool swap = false; + tree maybe_same; + + /* Move min of absolute values to int11. */ + if (absu_hwi (int01) < absu_hwi (int11)) + { + tmp = int01, int01 = int11, int11 = tmp; + alt0 = arg00, arg00 = arg10, arg10 = alt0; + maybe_same = arg01; + swap = true; + } + else + maybe_same = arg11; + + const unsigned HOST_WIDE_INT factor = absu_hwi (int11); + if (factor > 1 + && pow2p_hwi (factor) + && (int01 & (factor - 1)) == 0 + /* The remainder should not be a constant, otherwise we + end up folding i * 4 + 2 to (i * 2 + 1) * 2 which has + increased the number of multiplications necessary. */ + && TREE_CODE (arg10) != INTEGER_CST) + { + alt0 = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (arg00), arg00, + build_int_cst (TREE_TYPE (arg00), + int01 / int11)); + alt1 = arg10; + same = maybe_same; + if (swap) + maybe_same = alt0, alt0 = alt1, alt1 = maybe_same; + } + } + + if (!same) + return NULL_TREE; + + if (! ANY_INTEGRAL_TYPE_P (type) + || TYPE_OVERFLOW_WRAPS (type) + /* We are neither factoring zero nor minus one. */ + || TREE_CODE (same) == INTEGER_CST) + return fold_build2_loc (loc, MULT_EXPR, type, + fold_build2_loc (loc, code, type, + fold_convert_loc (loc, type, alt0), + fold_convert_loc (loc, type, alt1)), + fold_convert_loc (loc, type, same)); + + /* Same may be zero and thus the operation 'code' may overflow. Likewise + same may be minus one and thus the multiplication may overflow. Perform + the sum operation in an unsigned type. */ + tree utype = unsigned_type_for (type); + tree tem = fold_build2_loc (loc, code, utype, + fold_convert_loc (loc, utype, alt0), + fold_convert_loc (loc, utype, alt1)); + /* If the sum evaluated to a constant that is not -INF the multiplication + cannot overflow. */ + if (TREE_CODE (tem) == INTEGER_CST + && (wi::to_wide (tem) + != wi::min_value (TYPE_PRECISION (utype), SIGNED))) + return fold_build2_loc (loc, MULT_EXPR, type, + fold_convert (type, tem), same); + + /* Do not resort to unsigned multiplication because + we lose the no-overflow property of the expression. */ + return NULL_TREE; +} + +/* Subroutine of native_encode_expr. Encode the INTEGER_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_int (const_tree expr, unsigned char *ptr, int len, int off) +{ + tree type = TREE_TYPE (expr); + int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)); + int byte, offset, word, words; + unsigned char value; + + if ((off == -1 && total_bytes > len) || off >= total_bytes) + return 0; + if (off == -1) + off = 0; + + if (ptr == NULL) + /* Dry run. */ + return MIN (len, total_bytes - off); + + words = total_bytes / UNITS_PER_WORD; + + for (byte = 0; byte < total_bytes; byte++) + { + int bitpos = byte * BITS_PER_UNIT; + /* Extend EXPR according to TYPE_SIGN if the precision isn't a whole + number of bytes. */ + value = wi::extract_uhwi (wi::to_widest (expr), bitpos, BITS_PER_UNIT); + + if (total_bytes > UNITS_PER_WORD) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte; + if (offset >= off && offset - off < len) + ptr[offset - off] = value; + } + return MIN (len, total_bytes - off); +} + + +/* Subroutine of native_encode_expr. Encode the FIXED_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off) +{ + tree type = TREE_TYPE (expr); + scalar_mode mode = SCALAR_TYPE_MODE (type); + int total_bytes = GET_MODE_SIZE (mode); + FIXED_VALUE_TYPE value; + tree i_value, i_type; + + if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + return 0; + + i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1); + + if (NULL_TREE == i_type || TYPE_PRECISION (i_type) != total_bytes) + return 0; + + value = TREE_FIXED_CST (expr); + i_value = double_int_to_tree (i_type, value.data); + + return native_encode_int (i_value, ptr, len, off); +} + + +/* Subroutine of native_encode_expr. Encode the REAL_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_real (const_tree expr, unsigned char *ptr, int len, int off) +{ + tree type = TREE_TYPE (expr); + int total_bytes = GET_MODE_SIZE (SCALAR_FLOAT_TYPE_MODE (type)); + int byte, offset, word, words, bitpos; + unsigned char value; + + /* There are always 32 bits in each long, no matter the size of + the hosts long. We handle floating point representations with + up to 192 bits. */ + long tmp[6]; + + if ((off == -1 && total_bytes > len) || off >= total_bytes) + return 0; + if (off == -1) + off = 0; + + if (ptr == NULL) + /* Dry run. */ + return MIN (len, total_bytes - off); + + words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD; + + real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type)); + + for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; + bitpos += BITS_PER_UNIT) + { + byte = (bitpos / BITS_PER_UNIT) & 3; + value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31)); + + if (UNITS_PER_WORD < 4) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + { + offset = byte; + if (BYTES_BIG_ENDIAN) + { + /* Reverse bytes within each long, or within the entire float + if it's smaller than a long (for HFmode). */ + offset = MIN (3, total_bytes - 1) - offset; + gcc_assert (offset >= 0); + } + } + offset = offset + ((bitpos / BITS_PER_UNIT) & ~3); + if (offset >= off + && offset - off < len) + ptr[offset - off] = value; + } + return MIN (len, total_bytes - off); +} + +/* Subroutine of native_encode_expr. Encode the COMPLEX_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_complex (const_tree expr, unsigned char *ptr, int len, int off) +{ + int rsize, isize; + tree part; + + part = TREE_REALPART (expr); + rsize = native_encode_expr (part, ptr, len, off); + if (off == -1 && rsize == 0) + return 0; + part = TREE_IMAGPART (expr); + if (off != -1) + off = MAX (0, off - GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (part)))); + isize = native_encode_expr (part, ptr ? ptr + rsize : NULL, + len - rsize, off); + if (off == -1 && isize != rsize) + return 0; + return rsize + isize; +} + +/* Like native_encode_vector, but only encode the first COUNT elements. + The other arguments are as for native_encode_vector. */ + +static int +native_encode_vector_part (const_tree expr, unsigned char *ptr, int len, + int off, unsigned HOST_WIDE_INT count) +{ + tree itype = TREE_TYPE (TREE_TYPE (expr)); + if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (expr)) + && TYPE_PRECISION (itype) <= BITS_PER_UNIT) + { + /* This is the only case in which elements can be smaller than a byte. + Element 0 is always in the lsb of the containing byte. */ + unsigned int elt_bits = TYPE_PRECISION (itype); + int total_bytes = CEIL (elt_bits * count, BITS_PER_UNIT); + if ((off == -1 && total_bytes > len) || off >= total_bytes) + return 0; + + if (off == -1) + off = 0; + + /* Zero the buffer and then set bits later where necessary. */ + int extract_bytes = MIN (len, total_bytes - off); + if (ptr) + memset (ptr, 0, extract_bytes); + + unsigned int elts_per_byte = BITS_PER_UNIT / elt_bits; + unsigned int first_elt = off * elts_per_byte; + unsigned int extract_elts = extract_bytes * elts_per_byte; + for (unsigned int i = 0; i < extract_elts; ++i) + { + tree elt = VECTOR_CST_ELT (expr, first_elt + i); + if (TREE_CODE (elt) != INTEGER_CST) + return 0; + + if (ptr && wi::extract_uhwi (wi::to_wide (elt), 0, 1)) + { + unsigned int bit = i * elt_bits; + ptr[bit / BITS_PER_UNIT] |= 1 << (bit % BITS_PER_UNIT); + } + } + return extract_bytes; + } + + int offset = 0; + int size = GET_MODE_SIZE (SCALAR_TYPE_MODE (itype)); + for (unsigned HOST_WIDE_INT i = 0; i < count; i++) + { + if (off >= size) + { + off -= size; + continue; + } + tree elem = VECTOR_CST_ELT (expr, i); + int res = native_encode_expr (elem, ptr ? ptr + offset : NULL, + len - offset, off); + if ((off == -1 && res != size) || res == 0) + return 0; + offset += res; + if (offset >= len) + return (off == -1 && i < count - 1) ? 0 : offset; + if (off != -1) + off = 0; + } + return offset; +} + +/* Subroutine of native_encode_expr. Encode the VECTOR_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off) +{ + unsigned HOST_WIDE_INT count; + if (!VECTOR_CST_NELTS (expr).is_constant (&count)) + return 0; + return native_encode_vector_part (expr, ptr, len, off, count); +} + + +/* Subroutine of native_encode_expr. Encode the STRING_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_string (const_tree expr, unsigned char *ptr, int len, int off) +{ + tree type = TREE_TYPE (expr); + + /* Wide-char strings are encoded in target byte-order so native + encoding them is trivial. */ + if (BITS_PER_UNIT != CHAR_BIT + || TREE_CODE (type) != ARRAY_TYPE + || TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE + || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type))) + return 0; + + HOST_WIDE_INT total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (expr))); + if ((off == -1 && total_bytes > len) || off >= total_bytes) + return 0; + if (off == -1) + off = 0; + len = MIN (total_bytes - off, len); + if (ptr == NULL) + /* Dry run. */; + else + { + int written = 0; + if (off < TREE_STRING_LENGTH (expr)) + { + written = MIN (len, TREE_STRING_LENGTH (expr) - off); + memcpy (ptr, TREE_STRING_POINTER (expr) + off, written); + } + memset (ptr + written, 0, len - written); + } + return len; +} + + +/* Subroutine of fold_view_convert_expr. Encode the INTEGER_CST, REAL_CST, + FIXED_CST, COMPLEX_CST, STRING_CST, or VECTOR_CST specified by EXPR into + the buffer PTR of size LEN bytes. If PTR is NULL, don't actually store + anything, just do a dry run. Fail either if OFF is -1 and LEN isn't + sufficient to encode the entire EXPR, or if OFF is out of bounds. + Otherwise, start at byte offset OFF and encode at most LEN bytes. + Return the number of bytes placed in the buffer, or zero upon failure. */ + +int +native_encode_expr (const_tree expr, unsigned char *ptr, int len, int off) +{ + /* We don't support starting at negative offset and -1 is special. */ + if (off < -1) + return 0; + + switch (TREE_CODE (expr)) + { + case INTEGER_CST: + return native_encode_int (expr, ptr, len, off); + + case REAL_CST: + return native_encode_real (expr, ptr, len, off); + + case FIXED_CST: + return native_encode_fixed (expr, ptr, len, off); + + case COMPLEX_CST: + return native_encode_complex (expr, ptr, len, off); + + case VECTOR_CST: + return native_encode_vector (expr, ptr, len, off); + + case STRING_CST: + return native_encode_string (expr, ptr, len, off); + + default: + return 0; + } +} + +/* Try to find a type whose byte size is smaller or equal to LEN bytes larger + or equal to FIELDSIZE bytes, with underlying mode precision/size multiple + of BITS_PER_UNIT. As native_{interpret,encode}_int works in term of + machine modes, we can't just use build_nonstandard_integer_type. */ + +tree +find_bitfield_repr_type (int fieldsize, int len) +{ + machine_mode mode; + for (int pass = 0; pass < 2; pass++) + { + enum mode_class mclass = pass ? MODE_PARTIAL_INT : MODE_INT; + FOR_EACH_MODE_IN_CLASS (mode, mclass) + if (known_ge (GET_MODE_SIZE (mode), fieldsize) + && known_eq (GET_MODE_PRECISION (mode), + GET_MODE_BITSIZE (mode)) + && known_le (GET_MODE_SIZE (mode), len)) + { + tree ret = lang_hooks.types.type_for_mode (mode, 1); + if (ret && TYPE_MODE (ret) == mode) + return ret; + } + } + + for (int i = 0; i < NUM_INT_N_ENTS; i ++) + if (int_n_enabled_p[i] + && int_n_data[i].bitsize >= (unsigned) (BITS_PER_UNIT * fieldsize) + && int_n_trees[i].unsigned_type) + { + tree ret = int_n_trees[i].unsigned_type; + mode = TYPE_MODE (ret); + if (known_ge (GET_MODE_SIZE (mode), fieldsize) + && known_eq (GET_MODE_PRECISION (mode), + GET_MODE_BITSIZE (mode)) + && known_le (GET_MODE_SIZE (mode), len)) + return ret; + } + + return NULL_TREE; +} + +/* Similar to native_encode_expr, but also handle CONSTRUCTORs, VCEs, + NON_LVALUE_EXPRs and nops. If MASK is non-NULL (then PTR has + to be non-NULL and OFF zero), then in addition to filling the + bytes pointed by PTR with the value also clear any bits pointed + by MASK that are known to be initialized, keep them as is for + e.g. uninitialized padding bits or uninitialized fields. */ + +int +native_encode_initializer (tree init, unsigned char *ptr, int len, + int off, unsigned char *mask) +{ + int r; + + /* We don't support starting at negative offset and -1 is special. */ + if (off < -1 || init == NULL_TREE) + return 0; + + gcc_assert (mask == NULL || (off == 0 && ptr)); + + STRIP_NOPS (init); + switch (TREE_CODE (init)) + { + case VIEW_CONVERT_EXPR: + case NON_LVALUE_EXPR: + return native_encode_initializer (TREE_OPERAND (init, 0), ptr, len, off, + mask); + default: + r = native_encode_expr (init, ptr, len, off); + if (mask) + memset (mask, 0, r); + return r; + case CONSTRUCTOR: + tree type = TREE_TYPE (init); + HOST_WIDE_INT total_bytes = int_size_in_bytes (type); + if (total_bytes < 0) + return 0; + if ((off == -1 && total_bytes > len) || off >= total_bytes) + return 0; + int o = off == -1 ? 0 : off; + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree min_index; + unsigned HOST_WIDE_INT cnt; + HOST_WIDE_INT curpos = 0, fieldsize, valueinit = -1; + constructor_elt *ce; + + if (!TYPE_DOMAIN (type) + || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST) + return 0; + + fieldsize = int_size_in_bytes (TREE_TYPE (type)); + if (fieldsize <= 0) + return 0; + + min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); + if (ptr) + memset (ptr, '\0', MIN (total_bytes - off, len)); + + for (cnt = 0; ; cnt++) + { + tree val = NULL_TREE, index = NULL_TREE; + HOST_WIDE_INT pos = curpos, count = 0; + bool full = false; + if (vec_safe_iterate (CONSTRUCTOR_ELTS (init), cnt, &ce)) + { + val = ce->value; + index = ce->index; + } + else if (mask == NULL + || CONSTRUCTOR_NO_CLEARING (init) + || curpos >= total_bytes) + break; + else + pos = total_bytes; + + if (index && TREE_CODE (index) == RANGE_EXPR) + { + if (TREE_CODE (TREE_OPERAND (index, 0)) != INTEGER_CST + || TREE_CODE (TREE_OPERAND (index, 1)) != INTEGER_CST) + return 0; + offset_int wpos + = wi::sext (wi::to_offset (TREE_OPERAND (index, 0)) + - wi::to_offset (min_index), + TYPE_PRECISION (sizetype)); + wpos *= fieldsize; + if (!wi::fits_shwi_p (pos)) + return 0; + pos = wpos.to_shwi (); + offset_int wcount + = wi::sext (wi::to_offset (TREE_OPERAND (index, 1)) + - wi::to_offset (TREE_OPERAND (index, 0)), + TYPE_PRECISION (sizetype)); + if (!wi::fits_shwi_p (wcount)) + return 0; + count = wcount.to_shwi (); + } + else if (index) + { + if (TREE_CODE (index) != INTEGER_CST) + return 0; + offset_int wpos + = wi::sext (wi::to_offset (index) + - wi::to_offset (min_index), + TYPE_PRECISION (sizetype)); + wpos *= fieldsize; + if (!wi::fits_shwi_p (wpos)) + return 0; + pos = wpos.to_shwi (); + } + + if (mask && !CONSTRUCTOR_NO_CLEARING (init) && curpos != pos) + { + if (valueinit == -1) + { + tree zero = build_zero_cst (TREE_TYPE (type)); + r = native_encode_initializer (zero, ptr + curpos, + fieldsize, 0, + mask + curpos); + if (TREE_CODE (zero) == CONSTRUCTOR) + ggc_free (zero); + if (!r) + return 0; + valueinit = curpos; + curpos += fieldsize; + } + while (curpos != pos) + { + memcpy (ptr + curpos, ptr + valueinit, fieldsize); + memcpy (mask + curpos, mask + valueinit, fieldsize); + curpos += fieldsize; + } + } + + curpos = pos; + if (val) + do + { + if (off == -1 + || (curpos >= off + && (curpos + fieldsize + <= (HOST_WIDE_INT) off + len))) + { + if (full) + { + if (ptr) + memcpy (ptr + (curpos - o), ptr + (pos - o), + fieldsize); + if (mask) + memcpy (mask + curpos, mask + pos, fieldsize); + } + else if (!native_encode_initializer (val, + ptr + ? ptr + curpos - o + : NULL, + fieldsize, + off == -1 ? -1 + : 0, + mask + ? mask + curpos + : NULL)) + return 0; + else + { + full = true; + pos = curpos; + } + } + else if (curpos + fieldsize > off + && curpos < (HOST_WIDE_INT) off + len) + { + /* Partial overlap. */ + unsigned char *p = NULL; + int no = 0; + int l; + gcc_assert (mask == NULL); + if (curpos >= off) + { + if (ptr) + p = ptr + curpos - off; + l = MIN ((HOST_WIDE_INT) off + len - curpos, + fieldsize); + } + else + { + p = ptr; + no = off - curpos; + l = len; + } + if (!native_encode_initializer (val, p, l, no, NULL)) + return 0; + } + curpos += fieldsize; + } + while (count-- != 0); + } + return MIN (total_bytes - off, len); + } + else if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + { + unsigned HOST_WIDE_INT cnt; + constructor_elt *ce; + tree fld_base = TYPE_FIELDS (type); + tree to_free = NULL_TREE; + + gcc_assert (TREE_CODE (type) == RECORD_TYPE || mask == NULL); + if (ptr != NULL) + memset (ptr, '\0', MIN (total_bytes - o, len)); + for (cnt = 0; ; cnt++) + { + tree val = NULL_TREE, field = NULL_TREE; + HOST_WIDE_INT pos = 0, fieldsize; + unsigned HOST_WIDE_INT bpos = 0, epos = 0; + + if (to_free) + { + ggc_free (to_free); + to_free = NULL_TREE; + } + + if (vec_safe_iterate (CONSTRUCTOR_ELTS (init), cnt, &ce)) + { + val = ce->value; + field = ce->index; + if (field == NULL_TREE) + return 0; + + pos = int_byte_position (field); + if (off != -1 && (HOST_WIDE_INT) off + len <= pos) + continue; + } + else if (mask == NULL + || CONSTRUCTOR_NO_CLEARING (init)) + break; + else + pos = total_bytes; + + if (mask && !CONSTRUCTOR_NO_CLEARING (init)) + { + tree fld; + for (fld = fld_base; fld; fld = DECL_CHAIN (fld)) + { + if (TREE_CODE (fld) != FIELD_DECL) + continue; + if (fld == field) + break; + if (DECL_PADDING_P (fld)) + continue; + if (DECL_SIZE_UNIT (fld) == NULL_TREE + || !tree_fits_shwi_p (DECL_SIZE_UNIT (fld))) + return 0; + if (integer_zerop (DECL_SIZE_UNIT (fld))) + continue; + break; + } + if (fld == NULL_TREE) + { + if (ce == NULL) + break; + return 0; + } + fld_base = DECL_CHAIN (fld); + if (fld != field) + { + cnt--; + field = fld; + pos = int_byte_position (field); + val = build_zero_cst (TREE_TYPE (fld)); + if (TREE_CODE (val) == CONSTRUCTOR) + to_free = val; + } + } + + if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (field)) + && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))) + { + if (mask || off != -1) + return 0; + if (val == NULL_TREE) + continue; + if (TREE_CODE (TREE_TYPE (val)) != ARRAY_TYPE) + return 0; + fieldsize = int_size_in_bytes (TREE_TYPE (val)); + if (fieldsize < 0 + || (int) fieldsize != fieldsize + || (pos + fieldsize) > INT_MAX) + return 0; + if (pos + fieldsize > total_bytes) + { + if (ptr != NULL && total_bytes < len) + memset (ptr + total_bytes, '\0', + MIN (pos + fieldsize, len) - total_bytes); + total_bytes = pos + fieldsize; + } + } + else + { + if (DECL_SIZE_UNIT (field) == NULL_TREE + || !tree_fits_shwi_p (DECL_SIZE_UNIT (field))) + return 0; + fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field)); + } + if (fieldsize == 0) + continue; + + if (DECL_BIT_FIELD (field)) + { + if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field))) + return 0; + fieldsize = TYPE_PRECISION (TREE_TYPE (field)); + bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); + if (bpos % BITS_PER_UNIT) + bpos %= BITS_PER_UNIT; + else + bpos = 0; + fieldsize += bpos; + epos = fieldsize % BITS_PER_UNIT; + fieldsize += BITS_PER_UNIT - 1; + fieldsize /= BITS_PER_UNIT; + } + + if (off != -1 && pos + fieldsize <= off) + continue; + + if (val == NULL_TREE) + continue; + + if (DECL_BIT_FIELD (field)) + { + /* FIXME: Handle PDP endian. */ + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + return 0; + + if (TREE_CODE (val) != INTEGER_CST) + return 0; + + tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field); + tree repr_type = NULL_TREE; + HOST_WIDE_INT rpos = 0; + if (repr && INTEGRAL_TYPE_P (TREE_TYPE (repr))) + { + rpos = int_byte_position (repr); + repr_type = TREE_TYPE (repr); + } + else + { + repr_type = find_bitfield_repr_type (fieldsize, len); + if (repr_type == NULL_TREE) + return 0; + HOST_WIDE_INT repr_size = int_size_in_bytes (repr_type); + gcc_assert (repr_size > 0 && repr_size <= len); + if (pos + repr_size <= o + len) + rpos = pos; + else + { + rpos = o + len - repr_size; + gcc_assert (rpos <= pos); + } + } + + if (rpos > pos) + return 0; + wide_int w = wi::to_wide (val, TYPE_PRECISION (repr_type)); + int diff = (TYPE_PRECISION (repr_type) + - TYPE_PRECISION (TREE_TYPE (field))); + HOST_WIDE_INT bitoff = (pos - rpos) * BITS_PER_UNIT + bpos; + if (!BYTES_BIG_ENDIAN) + w = wi::lshift (w, bitoff); + else + w = wi::lshift (w, diff - bitoff); + val = wide_int_to_tree (repr_type, w); + + unsigned char buf[MAX_BITSIZE_MODE_ANY_INT + / BITS_PER_UNIT + 1]; + int l = native_encode_int (val, buf, sizeof buf, 0); + if (l * BITS_PER_UNIT != TYPE_PRECISION (repr_type)) + return 0; + + if (ptr == NULL) + continue; + + /* If the bitfield does not start at byte boundary, handle + the partial byte at the start. */ + if (bpos + && (off == -1 || (pos >= off && len >= 1))) + { + if (!BYTES_BIG_ENDIAN) + { + int msk = (1 << bpos) - 1; + buf[pos - rpos] &= ~msk; + buf[pos - rpos] |= ptr[pos - o] & msk; + if (mask) + { + if (fieldsize > 1 || epos == 0) + mask[pos] &= msk; + else + mask[pos] &= (msk | ~((1 << epos) - 1)); + } + } + else + { + int msk = (1 << (BITS_PER_UNIT - bpos)) - 1; + buf[pos - rpos] &= msk; + buf[pos - rpos] |= ptr[pos - o] & ~msk; + if (mask) + { + if (fieldsize > 1 || epos == 0) + mask[pos] &= ~msk; + else + mask[pos] &= (~msk + | ((1 << (BITS_PER_UNIT - epos)) + - 1)); + } + } + } + /* If the bitfield does not end at byte boundary, handle + the partial byte at the end. */ + if (epos + && (off == -1 + || pos + fieldsize <= (HOST_WIDE_INT) off + len)) + { + if (!BYTES_BIG_ENDIAN) + { + int msk = (1 << epos) - 1; + buf[pos - rpos + fieldsize - 1] &= msk; + buf[pos - rpos + fieldsize - 1] + |= ptr[pos + fieldsize - 1 - o] & ~msk; + if (mask && (fieldsize > 1 || bpos == 0)) + mask[pos + fieldsize - 1] &= ~msk; + } + else + { + int msk = (1 << (BITS_PER_UNIT - epos)) - 1; + buf[pos - rpos + fieldsize - 1] &= ~msk; + buf[pos - rpos + fieldsize - 1] + |= ptr[pos + fieldsize - 1 - o] & msk; + if (mask && (fieldsize > 1 || bpos == 0)) + mask[pos + fieldsize - 1] &= msk; + } + } + if (off == -1 + || (pos >= off + && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) + { + memcpy (ptr + pos - o, buf + (pos - rpos), fieldsize); + if (mask && (fieldsize > (bpos != 0) + (epos != 0))) + memset (mask + pos + (bpos != 0), 0, + fieldsize - (bpos != 0) - (epos != 0)); + } + else + { + /* Partial overlap. */ + HOST_WIDE_INT fsz = fieldsize; + gcc_assert (mask == NULL); + if (pos < off) + { + fsz -= (off - pos); + pos = off; + } + if (pos + fsz > (HOST_WIDE_INT) off + len) + fsz = (HOST_WIDE_INT) off + len - pos; + memcpy (ptr + pos - off, buf + (pos - rpos), fsz); + } + continue; + } + + if (off == -1 + || (pos >= off + && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) + { + int fldsize = fieldsize; + if (off == -1) + { + tree fld = DECL_CHAIN (field); + while (fld) + { + if (TREE_CODE (fld) == FIELD_DECL) + break; + fld = DECL_CHAIN (fld); + } + if (fld == NULL_TREE) + fldsize = len - pos; + } + r = native_encode_initializer (val, ptr ? ptr + pos - o + : NULL, + fldsize, + off == -1 ? -1 : 0, + mask ? mask + pos : NULL); + if (!r) + return 0; + if (off == -1 + && fldsize != fieldsize + && r > fieldsize + && pos + r > total_bytes) + total_bytes = pos + r; + } + else + { + /* Partial overlap. */ + unsigned char *p = NULL; + int no = 0; + int l; + gcc_assert (mask == NULL); + if (pos >= off) + { + if (ptr) + p = ptr + pos - off; + l = MIN ((HOST_WIDE_INT) off + len - pos, + fieldsize); + } + else + { + p = ptr; + no = off - pos; + l = len; + } + if (!native_encode_initializer (val, p, l, no, NULL)) + return 0; + } + } + return MIN (total_bytes - off, len); + } + return 0; + } +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as an INTEGER_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_int (tree type, const unsigned char *ptr, int len) +{ + int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)); + + if (total_bytes > len + || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + return NULL_TREE; + + wide_int result = wi::from_buffer (ptr, total_bytes); + + return wide_int_to_tree (type, result); +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a FIXED_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_fixed (tree type, const unsigned char *ptr, int len) +{ + scalar_mode mode = SCALAR_TYPE_MODE (type); + int total_bytes = GET_MODE_SIZE (mode); + double_int result; + FIXED_VALUE_TYPE fixed_value; + + if (total_bytes > len + || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + return NULL_TREE; + + result = double_int::from_buffer (ptr, total_bytes); + fixed_value = fixed_from_double_int (result, mode); + + return build_fixed (type, fixed_value); +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a REAL_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_real (tree type, const unsigned char *ptr, int len) +{ + scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (type); + int total_bytes = GET_MODE_SIZE (mode); + unsigned char value; + /* There are always 32 bits in each long, no matter the size of + the hosts long. We handle floating point representations with + up to 192 bits. */ + REAL_VALUE_TYPE r; + long tmp[6]; + + if (total_bytes > len || total_bytes > 24) + return NULL_TREE; + int words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD; + + memset (tmp, 0, sizeof (tmp)); + for (int bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; + bitpos += BITS_PER_UNIT) + { + /* Both OFFSET and BYTE index within a long; + bitpos indexes the whole float. */ + int offset, byte = (bitpos / BITS_PER_UNIT) & 3; + if (UNITS_PER_WORD < 4) + { + int word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + { + offset = byte; + if (BYTES_BIG_ENDIAN) + { + /* Reverse bytes within each long, or within the entire float + if it's smaller than a long (for HFmode). */ + offset = MIN (3, total_bytes - 1) - offset; + gcc_assert (offset >= 0); + } + } + value = ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)]; + + tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31); + } + + real_from_target (&r, tmp, mode); + tree ret = build_real (type, r); + if (MODE_COMPOSITE_P (mode)) + { + /* For floating point values in composite modes, punt if this folding + doesn't preserve bit representation. As the mode doesn't have fixed + precision while GCC pretends it does, there could be valid values that + GCC can't really represent accurately. See PR95450. */ + unsigned char buf[24]; + if (native_encode_expr (ret, buf, total_bytes, 0) != total_bytes + || memcmp (ptr, buf, total_bytes) != 0) + ret = NULL_TREE; + } + return ret; +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a COMPLEX_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_complex (tree type, const unsigned char *ptr, int len) +{ + tree etype, rpart, ipart; + int size; + + etype = TREE_TYPE (type); + size = GET_MODE_SIZE (SCALAR_TYPE_MODE (etype)); + if (size * 2 > len) + return NULL_TREE; + rpart = native_interpret_expr (etype, ptr, size); + if (!rpart) + return NULL_TREE; + ipart = native_interpret_expr (etype, ptr+size, size); + if (!ipart) + return NULL_TREE; + return build_complex (type, rpart, ipart); +} + +/* Read a vector of type TYPE from the target memory image given by BYTES, + which contains LEN bytes. The vector is known to be encodable using + NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements each. + + Return the vector on success, otherwise return null. */ + +static tree +native_interpret_vector_part (tree type, const unsigned char *bytes, + unsigned int len, unsigned int npatterns, + unsigned int nelts_per_pattern) +{ + tree elt_type = TREE_TYPE (type); + if (VECTOR_BOOLEAN_TYPE_P (type) + && TYPE_PRECISION (elt_type) <= BITS_PER_UNIT) + { + /* This is the only case in which elements can be smaller than a byte. + Element 0 is always in the lsb of the containing byte. */ + unsigned int elt_bits = TYPE_PRECISION (elt_type); + if (elt_bits * npatterns * nelts_per_pattern > len * BITS_PER_UNIT) + return NULL_TREE; + + tree_vector_builder builder (type, npatterns, nelts_per_pattern); + for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) + { + unsigned int bit_index = i * elt_bits; + unsigned int byte_index = bit_index / BITS_PER_UNIT; + unsigned int lsb = bit_index % BITS_PER_UNIT; + builder.quick_push (bytes[byte_index] & (1 << lsb) + ? build_all_ones_cst (elt_type) + : build_zero_cst (elt_type)); + } + return builder.build (); + } + + unsigned int elt_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (elt_type)); + if (elt_bytes * npatterns * nelts_per_pattern > len) + return NULL_TREE; + + tree_vector_builder builder (type, npatterns, nelts_per_pattern); + for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) + { + tree elt = native_interpret_expr (elt_type, bytes, elt_bytes); + if (!elt) + return NULL_TREE; + builder.quick_push (elt); + bytes += elt_bytes; + } + return builder.build (); +} + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a VECTOR_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_vector (tree type, const unsigned char *ptr, unsigned int len) +{ + tree etype; + unsigned int size; + unsigned HOST_WIDE_INT count; + + etype = TREE_TYPE (type); + size = GET_MODE_SIZE (SCALAR_TYPE_MODE (etype)); + if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&count) + || size * count > len) + return NULL_TREE; + + return native_interpret_vector_part (type, ptr, len, count, 1); +} + + +/* Subroutine of fold_view_convert_expr. Interpret the contents of + the buffer PTR of length LEN as a constant of type TYPE. For + INTEGRAL_TYPE_P we return an INTEGER_CST, for SCALAR_FLOAT_TYPE_P + we return a REAL_CST, etc... If the buffer cannot be interpreted, + return NULL_TREE. */ + +tree +native_interpret_expr (tree type, const unsigned char *ptr, int len) +{ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + return native_interpret_int (type, ptr, len); + + case REAL_TYPE: + return native_interpret_real (type, ptr, len); + + case FIXED_POINT_TYPE: + return native_interpret_fixed (type, ptr, len); + + case COMPLEX_TYPE: + return native_interpret_complex (type, ptr, len); + + case VECTOR_TYPE: + return native_interpret_vector (type, ptr, len); + + default: + return NULL_TREE; + } +} + +/* Returns true if we can interpret the contents of a native encoding + as TYPE. */ + +bool +can_native_interpret_type_p (tree type) +{ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + case FIXED_POINT_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case VECTOR_TYPE: + case OFFSET_TYPE: + return true; + default: + return false; + } +} + +/* Attempt to interpret aggregate of TYPE from bytes encoded in target + byte order at PTR + OFF with LEN bytes. Does not handle unions. */ + +tree +native_interpret_aggregate (tree type, const unsigned char *ptr, int off, + int len) +{ + vec<constructor_elt, va_gc> *elts = NULL; + if (TREE_CODE (type) == ARRAY_TYPE) + { + HOST_WIDE_INT eltsz = int_size_in_bytes (TREE_TYPE (type)); + if (eltsz < 0 || eltsz > len || TYPE_DOMAIN (type) == NULL_TREE) + return NULL_TREE; + + HOST_WIDE_INT cnt = 0; + if (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + { + if (!tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) + return NULL_TREE; + cnt = tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1; + } + if (eltsz == 0) + cnt = 0; + HOST_WIDE_INT pos = 0; + for (HOST_WIDE_INT i = 0; i < cnt; i++, pos += eltsz) + { + tree v = NULL_TREE; + if (pos >= len || pos + eltsz > len) + return NULL_TREE; + if (can_native_interpret_type_p (TREE_TYPE (type))) + { + v = native_interpret_expr (TREE_TYPE (type), + ptr + off + pos, eltsz); + if (v == NULL_TREE) + return NULL_TREE; + } + else if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) + v = native_interpret_aggregate (TREE_TYPE (type), ptr, off + pos, + eltsz); + if (v == NULL_TREE) + return NULL_TREE; + CONSTRUCTOR_APPEND_ELT (elts, size_int (i), v); + } + return build_constructor (type, elts); + } + if (TREE_CODE (type) != RECORD_TYPE) + return NULL_TREE; + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL || DECL_PADDING_P (field)) + continue; + tree fld = field; + HOST_WIDE_INT bitoff = 0, pos = 0, sz = 0; + int diff = 0; + tree v = NULL_TREE; + if (DECL_BIT_FIELD (field)) + { + fld = DECL_BIT_FIELD_REPRESENTATIVE (field); + if (fld && INTEGRAL_TYPE_P (TREE_TYPE (fld))) + { + poly_int64 bitoffset; + poly_uint64 field_offset, fld_offset; + if (poly_int_tree_p (DECL_FIELD_OFFSET (field), &field_offset) + && poly_int_tree_p (DECL_FIELD_OFFSET (fld), &fld_offset)) + bitoffset = (field_offset - fld_offset) * BITS_PER_UNIT; + else + bitoffset = 0; + bitoffset += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)) + - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld))); + diff = (TYPE_PRECISION (TREE_TYPE (fld)) + - TYPE_PRECISION (TREE_TYPE (field))); + if (!bitoffset.is_constant (&bitoff) + || bitoff < 0 + || bitoff > diff) + return NULL_TREE; + } + else + { + if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field))) + return NULL_TREE; + int fieldsize = TYPE_PRECISION (TREE_TYPE (field)); + int bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); + bpos %= BITS_PER_UNIT; + fieldsize += bpos; + fieldsize += BITS_PER_UNIT - 1; + fieldsize /= BITS_PER_UNIT; + tree repr_type = find_bitfield_repr_type (fieldsize, len); + if (repr_type == NULL_TREE) + return NULL_TREE; + sz = int_size_in_bytes (repr_type); + if (sz < 0 || sz > len) + return NULL_TREE; + pos = int_byte_position (field); + if (pos < 0 || pos > len || pos + fieldsize > len) + return NULL_TREE; + HOST_WIDE_INT rpos; + if (pos + sz <= len) + rpos = pos; + else + { + rpos = len - sz; + gcc_assert (rpos <= pos); + } + bitoff = (HOST_WIDE_INT) (pos - rpos) * BITS_PER_UNIT + bpos; + pos = rpos; + diff = (TYPE_PRECISION (repr_type) + - TYPE_PRECISION (TREE_TYPE (field))); + v = native_interpret_expr (repr_type, ptr + off + pos, sz); + if (v == NULL_TREE) + return NULL_TREE; + fld = NULL_TREE; + } + } + + if (fld) + { + sz = int_size_in_bytes (TREE_TYPE (fld)); + if (sz < 0 || sz > len) + return NULL_TREE; + tree byte_pos = byte_position (fld); + if (!tree_fits_shwi_p (byte_pos)) + return NULL_TREE; + pos = tree_to_shwi (byte_pos); + if (pos < 0 || pos > len || pos + sz > len) + return NULL_TREE; + } + if (fld == NULL_TREE) + /* Already handled above. */; + else if (can_native_interpret_type_p (TREE_TYPE (fld))) + { + v = native_interpret_expr (TREE_TYPE (fld), + ptr + off + pos, sz); + if (v == NULL_TREE) + return NULL_TREE; + } + else if (TREE_CODE (TREE_TYPE (fld)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (fld)) == ARRAY_TYPE) + v = native_interpret_aggregate (TREE_TYPE (fld), ptr, off + pos, sz); + if (v == NULL_TREE) + return NULL_TREE; + if (fld != field) + { + if (TREE_CODE (v) != INTEGER_CST) + return NULL_TREE; + + /* FIXME: Figure out how to handle PDP endian bitfields. */ + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + return NULL_TREE; + if (!BYTES_BIG_ENDIAN) + v = wide_int_to_tree (TREE_TYPE (field), + wi::lrshift (wi::to_wide (v), bitoff)); + else + v = wide_int_to_tree (TREE_TYPE (field), + wi::lrshift (wi::to_wide (v), + diff - bitoff)); + } + CONSTRUCTOR_APPEND_ELT (elts, field, v); + } + return build_constructor (type, elts); +} + +/* Routines for manipulation of native_encode_expr encoded data if the encoded + or extracted constant positions and/or sizes aren't byte aligned. */ + +/* Shift left the bytes in PTR of SZ elements by AMNT bits, carrying over the + bits between adjacent elements. AMNT should be within + [0, BITS_PER_UNIT). + Example, AMNT = 2: + 00011111|11100000 << 2 = 01111111|10000000 + PTR[1] | PTR[0] PTR[1] | PTR[0]. */ + +void +shift_bytes_in_array_left (unsigned char *ptr, unsigned int sz, + unsigned int amnt) +{ + if (amnt == 0) + return; + + unsigned char carry_over = 0U; + unsigned char carry_mask = (~0U) << (unsigned char) (BITS_PER_UNIT - amnt); + unsigned char clear_mask = (~0U) << amnt; + + for (unsigned int i = 0; i < sz; i++) + { + unsigned prev_carry_over = carry_over; + carry_over = (ptr[i] & carry_mask) >> (BITS_PER_UNIT - amnt); + + ptr[i] <<= amnt; + if (i != 0) + { + ptr[i] &= clear_mask; + ptr[i] |= prev_carry_over; + } + } +} + +/* Like shift_bytes_in_array_left but for big-endian. + Shift right the bytes in PTR of SZ elements by AMNT bits, carrying over the + bits between adjacent elements. AMNT should be within + [0, BITS_PER_UNIT). + Example, AMNT = 2: + 00011111|11100000 >> 2 = 00000111|11111000 + PTR[0] | PTR[1] PTR[0] | PTR[1]. */ + +void +shift_bytes_in_array_right (unsigned char *ptr, unsigned int sz, + unsigned int amnt) +{ + if (amnt == 0) + return; + + unsigned char carry_over = 0U; + unsigned char carry_mask = ~(~0U << amnt); + + for (unsigned int i = 0; i < sz; i++) + { + unsigned prev_carry_over = carry_over; + carry_over = ptr[i] & carry_mask; + + carry_over <<= (unsigned char) BITS_PER_UNIT - amnt; + ptr[i] >>= amnt; + ptr[i] |= prev_carry_over; + } +} + +/* Try to view-convert VECTOR_CST EXPR to VECTOR_TYPE TYPE by operating + directly on the VECTOR_CST encoding, in a way that works for variable- + length vectors. Return the resulting VECTOR_CST on success or null + on failure. */ + +static tree +fold_view_convert_vector_encoding (tree type, tree expr) +{ + tree expr_type = TREE_TYPE (expr); + poly_uint64 type_bits, expr_bits; + if (!poly_int_tree_p (TYPE_SIZE (type), &type_bits) + || !poly_int_tree_p (TYPE_SIZE (expr_type), &expr_bits)) + return NULL_TREE; + + poly_uint64 type_units = TYPE_VECTOR_SUBPARTS (type); + poly_uint64 expr_units = TYPE_VECTOR_SUBPARTS (expr_type); + unsigned int type_elt_bits = vector_element_size (type_bits, type_units); + unsigned int expr_elt_bits = vector_element_size (expr_bits, expr_units); + + /* We can only preserve the semantics of a stepped pattern if the new + vector element is an integer of the same size. */ + if (VECTOR_CST_STEPPED_P (expr) + && (!INTEGRAL_TYPE_P (type) || type_elt_bits != expr_elt_bits)) + return NULL_TREE; + + /* The number of bits needed to encode one element from every pattern + of the original vector. */ + unsigned int expr_sequence_bits + = VECTOR_CST_NPATTERNS (expr) * expr_elt_bits; + + /* The number of bits needed to encode one element from every pattern + of the result. */ + unsigned int type_sequence_bits + = least_common_multiple (expr_sequence_bits, type_elt_bits); + + /* Don't try to read more bytes than are available, which can happen + for constant-sized vectors if TYPE has larger elements than EXPR_TYPE. + The general VIEW_CONVERT handling can cope with that case, so there's + no point complicating things here. */ + unsigned int nelts_per_pattern = VECTOR_CST_NELTS_PER_PATTERN (expr); + unsigned int buffer_bytes = CEIL (nelts_per_pattern * type_sequence_bits, + BITS_PER_UNIT); + unsigned int buffer_bits = buffer_bytes * BITS_PER_UNIT; + if (known_gt (buffer_bits, expr_bits)) + return NULL_TREE; + + /* Get enough bytes of EXPR to form the new encoding. */ + auto_vec<unsigned char, 128> buffer (buffer_bytes); + buffer.quick_grow (buffer_bytes); + if (native_encode_vector_part (expr, buffer.address (), buffer_bytes, 0, + buffer_bits / expr_elt_bits) + != (int) buffer_bytes) + return NULL_TREE; + + /* Reencode the bytes as TYPE. */ + unsigned int type_npatterns = type_sequence_bits / type_elt_bits; + return native_interpret_vector_part (type, &buffer[0], buffer.length (), + type_npatterns, nelts_per_pattern); +} + +/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type + TYPE at compile-time. If we're unable to perform the conversion + return NULL_TREE. */ + +static tree +fold_view_convert_expr (tree type, tree expr) +{ + /* We support up to 512-bit values (for V8DFmode). */ + unsigned char buffer[64]; + int len; + + /* Check that the host and target are sane. */ + if (CHAR_BIT != 8 || BITS_PER_UNIT != 8) + return NULL_TREE; + + if (VECTOR_TYPE_P (type) && TREE_CODE (expr) == VECTOR_CST) + if (tree res = fold_view_convert_vector_encoding (type, expr)) + return res; + + len = native_encode_expr (expr, buffer, sizeof (buffer)); + if (len == 0) + return NULL_TREE; + + return native_interpret_expr (type, buffer, len); +} + +/* Build an expression for the address of T. Folds away INDIRECT_REF + to avoid confusing the gimplify process. */ + +tree +build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype) +{ + /* The size of the object is not relevant when talking about its address. */ + if (TREE_CODE (t) == WITH_SIZE_EXPR) + t = TREE_OPERAND (t, 0); + + if (TREE_CODE (t) == INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + + if (TREE_TYPE (t) != ptrtype) + t = build1_loc (loc, NOP_EXPR, ptrtype, t); + } + else if (TREE_CODE (t) == MEM_REF + && integer_zerop (TREE_OPERAND (t, 1))) + { + t = TREE_OPERAND (t, 0); + + if (TREE_TYPE (t) != ptrtype) + t = fold_convert_loc (loc, ptrtype, t); + } + else if (TREE_CODE (t) == MEM_REF + && TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST) + return fold_binary (POINTER_PLUS_EXPR, ptrtype, + TREE_OPERAND (t, 0), + convert_to_ptrofftype (TREE_OPERAND (t, 1))); + else if (TREE_CODE (t) == VIEW_CONVERT_EXPR) + { + t = build_fold_addr_expr_loc (loc, TREE_OPERAND (t, 0)); + + if (TREE_TYPE (t) != ptrtype) + t = fold_convert_loc (loc, ptrtype, t); + } + else + t = build1_loc (loc, ADDR_EXPR, ptrtype, t); + + return t; +} + +/* Build an expression for the address of T. */ + +tree +build_fold_addr_expr_loc (location_t loc, tree t) +{ + tree ptrtype = build_pointer_type (TREE_TYPE (t)); + + return build_fold_addr_expr_with_type_loc (loc, t, ptrtype); +} + +/* Fold a unary expression of code CODE and type TYPE with operand + OP0. Return the folded expression if folding is successful. + Otherwise, return NULL_TREE. */ + +tree +fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) +{ + tree tem; + tree arg0; + enum tree_code_class kind = TREE_CODE_CLASS (code); + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 1); + + arg0 = op0; + if (arg0) + { + if (CONVERT_EXPR_CODE_P (code) + || code == FLOAT_EXPR || code == ABS_EXPR || code == NEGATE_EXPR) + { + /* Don't use STRIP_NOPS, because signedness of argument type + matters. */ + STRIP_SIGN_NOPS (arg0); + } + else + { + /* Strip any conversions that don't change the mode. This + is safe for every expression, except for a comparison + expression because its signedness is derived from its + operands. + + Note that this is done as an internal manipulation within + the constant folder, in order to find the simplest + representation of the arguments so that their form can be + studied. In any cases, the appropriate type conversions + should be put back in the tree that will get out of the + constant folder. */ + STRIP_NOPS (arg0); + } + + if (CONSTANT_CLASS_P (arg0)) + { + tree tem = const_unop (code, type, arg0); + if (tem) + { + if (TREE_TYPE (tem) != type) + tem = fold_convert_loc (loc, type, tem); + return tem; + } + } + } + + tem = generic_simplify (loc, code, type, op0); + if (tem) + return tem; + + if (TREE_CODE_CLASS (code) == tcc_unary) + { + if (TREE_CODE (arg0) == COMPOUND_EXPR) + return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), + fold_build1_loc (loc, code, type, + fold_convert_loc (loc, TREE_TYPE (op0), + TREE_OPERAND (arg0, 1)))); + else if (TREE_CODE (arg0) == COND_EXPR) + { + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg02 = TREE_OPERAND (arg0, 2); + if (! VOID_TYPE_P (TREE_TYPE (arg01))) + arg01 = fold_build1_loc (loc, code, type, + fold_convert_loc (loc, + TREE_TYPE (op0), arg01)); + if (! VOID_TYPE_P (TREE_TYPE (arg02))) + arg02 = fold_build1_loc (loc, code, type, + fold_convert_loc (loc, + TREE_TYPE (op0), arg02)); + tem = fold_build3_loc (loc, COND_EXPR, type, TREE_OPERAND (arg0, 0), + arg01, arg02); + + /* If this was a conversion, and all we did was to move into + inside the COND_EXPR, bring it back out. But leave it if + it is a conversion from integer to integer and the + result precision is no wider than a word since such a + conversion is cheap and may be optimized away by combine, + while it couldn't if it were outside the COND_EXPR. Then return + so we don't get into an infinite recursion loop taking the + conversion out and then back in. */ + + if ((CONVERT_EXPR_CODE_P (code) + || code == NON_LVALUE_EXPR) + && TREE_CODE (tem) == COND_EXPR + && TREE_CODE (TREE_OPERAND (tem, 1)) == code + && TREE_CODE (TREE_OPERAND (tem, 2)) == code + && ! VOID_TYPE_P (TREE_OPERAND (tem, 1)) + && ! VOID_TYPE_P (TREE_OPERAND (tem, 2)) + && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)) + == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0))) + && (! (INTEGRAL_TYPE_P (TREE_TYPE (tem)) + && (INTEGRAL_TYPE_P + (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)))) + && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD) + || flag_syntax_only)) + tem = build1_loc (loc, code, type, + build3 (COND_EXPR, + TREE_TYPE (TREE_OPERAND + (TREE_OPERAND (tem, 1), 0)), + TREE_OPERAND (tem, 0), + TREE_OPERAND (TREE_OPERAND (tem, 1), 0), + TREE_OPERAND (TREE_OPERAND (tem, 2), + 0))); + return tem; + } + } + + switch (code) + { + case NON_LVALUE_EXPR: + if (!maybe_lvalue_p (op0)) + return fold_convert_loc (loc, type, op0); + return NULL_TREE; + + CASE_CONVERT: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + if (COMPARISON_CLASS_P (op0)) + { + /* If we have (type) (a CMP b) and type is an integral type, return + new expression involving the new type. Canonicalize + (type) (a CMP b) to (a CMP b) ? (type) true : (type) false for + non-integral type. + Do not fold the result as that would not simplify further, also + folding again results in recursions. */ + if (TREE_CODE (type) == BOOLEAN_TYPE) + return build2_loc (loc, TREE_CODE (op0), type, + TREE_OPERAND (op0, 0), + TREE_OPERAND (op0, 1)); + else if (!INTEGRAL_TYPE_P (type) && !VOID_TYPE_P (type) + && TREE_CODE (type) != VECTOR_TYPE) + return build3_loc (loc, COND_EXPR, type, op0, + constant_boolean_node (true, type), + constant_boolean_node (false, type)); + } + + /* Handle (T *)&A.B.C for A being of type T and B and C + living at offset zero. This occurs frequently in + C++ upcasting and then accessing the base. */ + if (TREE_CODE (op0) == ADDR_EXPR + && POINTER_TYPE_P (type) + && handled_component_p (TREE_OPERAND (op0, 0))) + { + poly_int64 bitsize, bitpos; + tree offset; + machine_mode mode; + int unsignedp, reversep, volatilep; + tree base + = get_inner_reference (TREE_OPERAND (op0, 0), &bitsize, &bitpos, + &offset, &mode, &unsignedp, &reversep, + &volatilep); + /* If the reference was to a (constant) zero offset, we can use + the address of the base if it has the same base type + as the result type and the pointer type is unqualified. */ + if (!offset + && known_eq (bitpos, 0) + && (TYPE_MAIN_VARIANT (TREE_TYPE (type)) + == TYPE_MAIN_VARIANT (TREE_TYPE (base))) + && TYPE_QUALS (type) == TYPE_UNQUALIFIED) + return fold_convert_loc (loc, type, + build_fold_addr_expr_loc (loc, base)); + } + + if (TREE_CODE (op0) == MODIFY_EXPR + && TREE_CONSTANT (TREE_OPERAND (op0, 1)) + /* Detect assigning a bitfield. */ + && !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF + && DECL_BIT_FIELD + (TREE_OPERAND (TREE_OPERAND (op0, 0), 1)))) + { + /* Don't leave an assignment inside a conversion + unless assigning a bitfield. */ + tem = fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 1)); + /* First do the assignment, then return converted constant. */ + tem = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (tem), op0, tem); + suppress_warning (tem /* What warning? */); + TREE_USED (tem) = 1; + return tem; + } + + /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer + constants (if x has signed type, the sign bit cannot be set + in c). This folds extension into the BIT_AND_EXPR. + ??? We don't do it for BOOLEAN_TYPE or ENUMERAL_TYPE because they + very likely don't have maximal range for their precision and this + transformation effectively doesn't preserve non-maximal ranges. */ + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (op0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST) + { + tree and_expr = op0; + tree and0 = TREE_OPERAND (and_expr, 0); + tree and1 = TREE_OPERAND (and_expr, 1); + int change = 0; + + if (TYPE_UNSIGNED (TREE_TYPE (and_expr)) + || (TYPE_PRECISION (type) + <= TYPE_PRECISION (TREE_TYPE (and_expr)))) + change = 1; + else if (TYPE_PRECISION (TREE_TYPE (and1)) + <= HOST_BITS_PER_WIDE_INT + && tree_fits_uhwi_p (and1)) + { + unsigned HOST_WIDE_INT cst; + + cst = tree_to_uhwi (and1); + cst &= HOST_WIDE_INT_M1U + << (TYPE_PRECISION (TREE_TYPE (and1)) - 1); + change = (cst == 0); + if (change + && !flag_syntax_only + && (load_extend_op (TYPE_MODE (TREE_TYPE (and0))) + == ZERO_EXTEND)) + { + tree uns = unsigned_type_for (TREE_TYPE (and0)); + and0 = fold_convert_loc (loc, uns, and0); + and1 = fold_convert_loc (loc, uns, and1); + } + } + if (change) + { + tem = force_fit_type (type, wi::to_widest (and1), 0, + TREE_OVERFLOW (and1)); + return fold_build2_loc (loc, BIT_AND_EXPR, type, + fold_convert_loc (loc, type, and0), tem); + } + } + + /* Convert (T1)(X p+ Y) into ((T1)X p+ Y), for pointer type, when the new + cast (T1)X will fold away. We assume that this happens when X itself + is a cast. */ + if (POINTER_TYPE_P (type) + && TREE_CODE (arg0) == POINTER_PLUS_EXPR + && CONVERT_EXPR_P (TREE_OPERAND (arg0, 0))) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + + /* If -fsanitize=alignment, avoid this optimization in GENERIC + when the pointed type needs higher alignment than + the p+ first operand's pointed type. */ + if (!in_gimple_form + && sanitize_flags_p (SANITIZE_ALIGNMENT) + && (min_align_of_type (TREE_TYPE (type)) + > min_align_of_type (TREE_TYPE (TREE_TYPE (arg00))))) + return NULL_TREE; + + arg00 = fold_convert_loc (loc, type, arg00); + return fold_build_pointer_plus_loc (loc, arg00, arg01); + } + + /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types + of the same precision, and X is an integer type not narrower than + types T1 or T2, i.e. the cast (T2)X isn't an extension. */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (op0) == BIT_NOT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && CONVERT_EXPR_P (TREE_OPERAND (op0, 0)) + && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0))) + { + tem = TREE_OPERAND (TREE_OPERAND (op0, 0), 0); + if (INTEGRAL_TYPE_P (TREE_TYPE (tem)) + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (tem))) + return fold_build1_loc (loc, BIT_NOT_EXPR, type, + fold_convert_loc (loc, type, tem)); + } + + /* Convert (T1)(X * Y) into (T1)X * (T1)Y if T1 is narrower than the + type of X and Y (integer types only). */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (op0) == MULT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (op0))) + { + /* Be careful not to introduce new overflows. */ + tree mult_type; + if (TYPE_OVERFLOW_WRAPS (type)) + mult_type = type; + else + mult_type = unsigned_type_for (type); + + if (TYPE_PRECISION (mult_type) < TYPE_PRECISION (TREE_TYPE (op0))) + { + tem = fold_build2_loc (loc, MULT_EXPR, mult_type, + fold_convert_loc (loc, mult_type, + TREE_OPERAND (op0, 0)), + fold_convert_loc (loc, mult_type, + TREE_OPERAND (op0, 1))); + return fold_convert_loc (loc, type, tem); + } + } + + return NULL_TREE; + + case VIEW_CONVERT_EXPR: + if (TREE_CODE (op0) == MEM_REF) + { + if (TYPE_ALIGN (TREE_TYPE (op0)) != TYPE_ALIGN (type)) + type = build_aligned_type (type, TYPE_ALIGN (TREE_TYPE (op0))); + tem = fold_build2_loc (loc, MEM_REF, type, + TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1)); + REF_REVERSE_STORAGE_ORDER (tem) = REF_REVERSE_STORAGE_ORDER (op0); + return tem; + } + + return NULL_TREE; + + case NEGATE_EXPR: + tem = fold_negate_expr (loc, arg0); + if (tem) + return fold_convert_loc (loc, type, tem); + return NULL_TREE; + + case ABS_EXPR: + /* Convert fabs((double)float) into (double)fabsf(float). */ + if (TREE_CODE (arg0) == NOP_EXPR + && TREE_CODE (type) == REAL_TYPE) + { + tree targ0 = strip_float_extensions (arg0); + if (targ0 != arg0) + return fold_convert_loc (loc, type, + fold_build1_loc (loc, ABS_EXPR, + TREE_TYPE (targ0), + targ0)); + } + return NULL_TREE; + + case BIT_NOT_EXPR: + /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type, + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 0))))) + return fold_build2_loc (loc, BIT_XOR_EXPR, type, tem, + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 1))); + else if (TREE_CODE (arg0) == BIT_XOR_EXPR + && (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type, + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 1))))) + return fold_build2_loc (loc, BIT_XOR_EXPR, type, + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 0)), tem); + + return NULL_TREE; + + case TRUTH_NOT_EXPR: + /* Note that the operand of this must be an int + and its values must be 0 or 1. + ("true" is a fixed value perhaps depending on the language, + but we don't handle values other than 1 correctly yet.) */ + tem = fold_truth_not_expr (loc, arg0); + if (!tem) + return NULL_TREE; + return fold_convert_loc (loc, type, tem); + + case INDIRECT_REF: + /* Fold *&X to X if X is an lvalue. */ + if (TREE_CODE (op0) == ADDR_EXPR) + { + tree op00 = TREE_OPERAND (op0, 0); + if ((VAR_P (op00) + || TREE_CODE (op00) == PARM_DECL + || TREE_CODE (op00) == RESULT_DECL) + && !TREE_READONLY (op00)) + return op00; + } + return NULL_TREE; + + default: + return NULL_TREE; + } /* switch (code) */ +} + + +/* If the operation was a conversion do _not_ mark a resulting constant + with TREE_OVERFLOW if the original constant was not. These conversions + have implementation defined behavior and retaining the TREE_OVERFLOW + flag here would confuse later passes such as VRP. */ +tree +fold_unary_ignore_overflow_loc (location_t loc, enum tree_code code, + tree type, tree op0) +{ + tree res = fold_unary_loc (loc, code, type, op0); + if (res + && TREE_CODE (res) == INTEGER_CST + && TREE_CODE (op0) == INTEGER_CST + && CONVERT_EXPR_CODE_P (code)) + TREE_OVERFLOW (res) = TREE_OVERFLOW (op0); + + return res; +} + +/* Fold a binary bitwise/truth expression of code CODE and type TYPE with + operands OP0 and OP1. LOC is the location of the resulting expression. + ARG0 and ARG1 are the NOP_STRIPed results of OP0 and OP1. + Return the folded expression if folding is successful. Otherwise, + return NULL_TREE. */ +static tree +fold_truth_andor (location_t loc, enum tree_code code, tree type, + tree arg0, tree arg1, tree op0, tree op1) +{ + tree tem; + + /* We only do these simplifications if we are optimizing. */ + if (!optimize) + return NULL_TREE; + + /* Check for things like (A || B) && (A || C). We can convert this + to A || (B && C). Note that either operator can be any of the four + truth and/or operations and the transformation will still be + valid. Also note that we only care about order for the + ANDIF and ORIF operators. If B contains side effects, this + might change the truth-value of A. */ + if (TREE_CODE (arg0) == TREE_CODE (arg1) + && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR + || TREE_CODE (arg0) == TRUTH_ORIF_EXPR + || TREE_CODE (arg0) == TRUTH_AND_EXPR + || TREE_CODE (arg0) == TRUTH_OR_EXPR) + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1))) + { + tree a00 = TREE_OPERAND (arg0, 0); + tree a01 = TREE_OPERAND (arg0, 1); + tree a10 = TREE_OPERAND (arg1, 0); + tree a11 = TREE_OPERAND (arg1, 1); + int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR + || TREE_CODE (arg0) == TRUTH_AND_EXPR) + && (code == TRUTH_AND_EXPR + || code == TRUTH_OR_EXPR)); + + if (operand_equal_p (a00, a10, 0)) + return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, + fold_build2_loc (loc, code, type, a01, a11)); + else if (commutative && operand_equal_p (a00, a11, 0)) + return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, + fold_build2_loc (loc, code, type, a01, a10)); + else if (commutative && operand_equal_p (a01, a10, 0)) + return fold_build2_loc (loc, TREE_CODE (arg0), type, a01, + fold_build2_loc (loc, code, type, a00, a11)); + + /* This case if tricky because we must either have commutative + operators or else A10 must not have side-effects. */ + + else if ((commutative || ! TREE_SIDE_EFFECTS (a10)) + && operand_equal_p (a01, a11, 0)) + return fold_build2_loc (loc, TREE_CODE (arg0), type, + fold_build2_loc (loc, code, type, a00, a10), + a01); + } + + /* See if we can build a range comparison. */ + if ((tem = fold_range_test (loc, code, type, op0, op1)) != 0) + return tem; + + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR) + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR)) + { + tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true); + if (tem) + return fold_build2_loc (loc, code, type, tem, arg1); + } + + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR) + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR)) + { + tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false); + if (tem) + return fold_build2_loc (loc, code, type, arg0, tem); + } + + /* Check for the possibility of merging component references. If our + lhs is another similar operation, try to merge its rhs with our + rhs. Then try to merge our lhs and rhs. */ + if (TREE_CODE (arg0) == code + && (tem = fold_truth_andor_1 (loc, code, type, + TREE_OPERAND (arg0, 1), arg1)) != 0) + return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem); + + if ((tem = fold_truth_andor_1 (loc, code, type, arg0, arg1)) != 0) + return tem; + + bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT; + if (param_logical_op_non_short_circuit != -1) + logical_op_non_short_circuit + = param_logical_op_non_short_circuit; + if (logical_op_non_short_circuit + && !sanitize_coverage_p () + && (code == TRUTH_AND_EXPR + || code == TRUTH_ANDIF_EXPR + || code == TRUTH_OR_EXPR + || code == TRUTH_ORIF_EXPR)) + { + enum tree_code ncode, icode; + + ncode = (code == TRUTH_ANDIF_EXPR || code == TRUTH_AND_EXPR) + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR; + icode = ncode == TRUTH_AND_EXPR ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; + + /* Transform ((A AND-IF B) AND[-IF] C) into (A AND-IF (B AND C)), + or ((A OR-IF B) OR[-IF] C) into (A OR-IF (B OR C)) + We don't want to pack more than two leafs to a non-IF AND/OR + expression. + If tree-code of left-hand operand isn't an AND/OR-IF code and not + equal to IF-CODE, then we don't want to add right-hand operand. + If the inner right-hand side of left-hand operand has + side-effects, or isn't simple, then we can't add to it, + as otherwise we might destroy if-sequence. */ + if (TREE_CODE (arg0) == icode + && simple_operand_p_2 (arg1) + /* Needed for sequence points to handle trappings, and + side-effects. */ + && simple_operand_p_2 (TREE_OPERAND (arg0, 1))) + { + tem = fold_build2_loc (loc, ncode, type, TREE_OPERAND (arg0, 1), + arg1); + return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0), + tem); + } + /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C), + or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */ + else if (TREE_CODE (arg1) == icode + && simple_operand_p_2 (arg0) + /* Needed for sequence points to handle trappings, and + side-effects. */ + && simple_operand_p_2 (TREE_OPERAND (arg1, 0))) + { + tem = fold_build2_loc (loc, ncode, type, + arg0, TREE_OPERAND (arg1, 0)); + return fold_build2_loc (loc, icode, type, tem, + TREE_OPERAND (arg1, 1)); + } + /* Transform (A AND-IF B) into (A AND B), or (A OR-IF B) + into (A OR B). + For sequence point consistancy, we need to check for trapping, + and side-effects. */ + else if (code == icode && simple_operand_p_2 (arg0) + && simple_operand_p_2 (arg1)) + return fold_build2_loc (loc, ncode, type, arg0, arg1); + } + + return NULL_TREE; +} + +/* Helper that tries to canonicalize the comparison ARG0 CODE ARG1 + by changing CODE to reduce the magnitude of constants involved in + ARG0 of the comparison. + Returns a canonicalized comparison tree if a simplification was + possible, otherwise returns NULL_TREE. + Set *STRICT_OVERFLOW_P to true if the canonicalization is only + valid if signed overflow is undefined. */ + +static tree +maybe_canonicalize_comparison_1 (location_t loc, enum tree_code code, tree type, + tree arg0, tree arg1, + bool *strict_overflow_p) +{ + enum tree_code code0 = TREE_CODE (arg0); + tree t, cst0 = NULL_TREE; + int sgn0; + + /* Match A +- CST code arg1. We can change this only if overflow + is undefined. */ + if (!((ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))) + /* In principle pointers also have undefined overflow behavior, + but that causes problems elsewhere. */ + && !POINTER_TYPE_P (TREE_TYPE (arg0)) + && (code0 == MINUS_EXPR + || code0 == PLUS_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)) + return NULL_TREE; + + /* Identify the constant in arg0 and its sign. */ + cst0 = TREE_OPERAND (arg0, 1); + sgn0 = tree_int_cst_sgn (cst0); + + /* Overflowed constants and zero will cause problems. */ + if (integer_zerop (cst0) + || TREE_OVERFLOW (cst0)) + return NULL_TREE; + + /* See if we can reduce the magnitude of the constant in + arg0 by changing the comparison code. */ + /* A - CST < arg1 -> A - CST-1 <= arg1. */ + if (code == LT_EXPR + && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR)) + code = LE_EXPR; + /* A + CST > arg1 -> A + CST-1 >= arg1. */ + else if (code == GT_EXPR + && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR)) + code = GE_EXPR; + /* A + CST <= arg1 -> A + CST-1 < arg1. */ + else if (code == LE_EXPR + && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR)) + code = LT_EXPR; + /* A - CST >= arg1 -> A - CST-1 > arg1. */ + else if (code == GE_EXPR + && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR)) + code = GT_EXPR; + else + return NULL_TREE; + *strict_overflow_p = true; + + /* Now build the constant reduced in magnitude. But not if that + would produce one outside of its types range. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (cst0)) + && ((sgn0 == 1 + && TYPE_MIN_VALUE (TREE_TYPE (cst0)) + && tree_int_cst_equal (cst0, TYPE_MIN_VALUE (TREE_TYPE (cst0)))) + || (sgn0 == -1 + && TYPE_MAX_VALUE (TREE_TYPE (cst0)) + && tree_int_cst_equal (cst0, TYPE_MAX_VALUE (TREE_TYPE (cst0)))))) + return NULL_TREE; + + t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR, + cst0, build_int_cst (TREE_TYPE (cst0), 1)); + t = fold_build2_loc (loc, code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t); + t = fold_convert (TREE_TYPE (arg1), t); + + return fold_build2_loc (loc, code, type, t, arg1); +} + +/* Canonicalize the comparison ARG0 CODE ARG1 with type TYPE with undefined + overflow further. Try to decrease the magnitude of constants involved + by changing LE_EXPR and GE_EXPR to LT_EXPR and GT_EXPR or vice versa + and put sole constants at the second argument position. + Returns the canonicalized tree if changed, otherwise NULL_TREE. */ + +static tree +maybe_canonicalize_comparison (location_t loc, enum tree_code code, tree type, + tree arg0, tree arg1) +{ + tree t; + bool strict_overflow_p; + const char * const warnmsg = G_("assuming signed overflow does not occur " + "when reducing constant in comparison"); + + /* Try canonicalization by simplifying arg0. */ + strict_overflow_p = false; + t = maybe_canonicalize_comparison_1 (loc, code, type, arg0, arg1, + &strict_overflow_p); + if (t) + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); + return t; + } + + /* Try canonicalization by simplifying arg1 using the swapped + comparison. */ + code = swap_tree_comparison (code); + strict_overflow_p = false; + t = maybe_canonicalize_comparison_1 (loc, code, type, arg1, arg0, + &strict_overflow_p); + if (t && strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); + return t; +} + +/* Return whether BASE + OFFSET + BITPOS may wrap around the address + space. This is used to avoid issuing overflow warnings for + expressions like &p->x which cannot wrap. */ + +static bool +pointer_may_wrap_p (tree base, tree offset, poly_int64 bitpos) +{ + if (!POINTER_TYPE_P (TREE_TYPE (base))) + return true; + + if (maybe_lt (bitpos, 0)) + return true; + + poly_wide_int wi_offset; + int precision = TYPE_PRECISION (TREE_TYPE (base)); + if (offset == NULL_TREE) + wi_offset = wi::zero (precision); + else if (!poly_int_tree_p (offset) || TREE_OVERFLOW (offset)) + return true; + else + wi_offset = wi::to_poly_wide (offset); + + wi::overflow_type overflow; + poly_wide_int units = wi::shwi (bits_to_bytes_round_down (bitpos), + precision); + poly_wide_int total = wi::add (wi_offset, units, UNSIGNED, &overflow); + if (overflow) + return true; + + poly_uint64 total_hwi, size; + if (!total.to_uhwi (&total_hwi) + || !poly_int_tree_p (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (base))), + &size) + || known_eq (size, 0U)) + return true; + + if (known_le (total_hwi, size)) + return false; + + /* We can do slightly better for SIZE if we have an ADDR_EXPR of an + array. */ + if (TREE_CODE (base) == ADDR_EXPR + && poly_int_tree_p (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (base, 0))), + &size) + && maybe_ne (size, 0U) + && known_le (total_hwi, size)) + return false; + + return true; +} + +/* Return a positive integer when the symbol DECL is known to have + a nonzero address, zero when it's known not to (e.g., it's a weak + symbol), and a negative integer when the symbol is not yet in the + symbol table and so whether or not its address is zero is unknown. + For function local objects always return positive integer. */ +static int +maybe_nonzero_address (tree decl) +{ + /* Normally, don't do anything for variables and functions before symtab is + built; it is quite possible that DECL will be declared weak later. + But if folding_initializer, we need a constant answer now, so create + the symtab entry and prevent later weak declaration. */ + if (DECL_P (decl) && decl_in_symtab_p (decl)) + if (struct symtab_node *symbol + = (folding_initializer + ? symtab_node::get_create (decl) + : symtab_node::get (decl))) + return symbol->nonzero_address (); + + /* Function local objects are never NULL. */ + if (DECL_P (decl) + && (DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL + && auto_var_in_fn_p (decl, DECL_CONTEXT (decl)))) + return 1; + + return -1; +} + +/* Subroutine of fold_binary. This routine performs all of the + transformations that are common to the equality/inequality + operators (EQ_EXPR and NE_EXPR) and the ordering operators + (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR). Callers other than + fold_binary should call fold_binary. Fold a comparison with + tree code CODE and type TYPE with operands OP0 and OP1. Return + the folded comparison or NULL_TREE. */ + +static tree +fold_comparison (location_t loc, enum tree_code code, tree type, + tree op0, tree op1) +{ + const bool equality_code = (code == EQ_EXPR || code == NE_EXPR); + tree arg0, arg1, tem; + + arg0 = op0; + arg1 = op1; + + STRIP_SIGN_NOPS (arg0); + STRIP_SIGN_NOPS (arg1); + + /* For comparisons of pointers we can decompose it to a compile time + comparison of the base objects and the offsets into the object. + This requires at least one operand being an ADDR_EXPR or a + POINTER_PLUS_EXPR to do more than the operand_equal_p test below. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) + && (TREE_CODE (arg0) == ADDR_EXPR + || TREE_CODE (arg1) == ADDR_EXPR + || TREE_CODE (arg0) == POINTER_PLUS_EXPR + || TREE_CODE (arg1) == POINTER_PLUS_EXPR)) + { + tree base0, base1, offset0 = NULL_TREE, offset1 = NULL_TREE; + poly_int64 bitsize, bitpos0 = 0, bitpos1 = 0; + machine_mode mode; + int volatilep, reversep, unsignedp; + bool indirect_base0 = false, indirect_base1 = false; + + /* Get base and offset for the access. Strip ADDR_EXPR for + get_inner_reference, but put it back by stripping INDIRECT_REF + off the base object if possible. indirect_baseN will be true + if baseN is not an address but refers to the object itself. */ + base0 = arg0; + if (TREE_CODE (arg0) == ADDR_EXPR) + { + base0 + = get_inner_reference (TREE_OPERAND (arg0, 0), + &bitsize, &bitpos0, &offset0, &mode, + &unsignedp, &reversep, &volatilep); + if (TREE_CODE (base0) == INDIRECT_REF) + base0 = TREE_OPERAND (base0, 0); + else + indirect_base0 = true; + } + else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR) + { + base0 = TREE_OPERAND (arg0, 0); + STRIP_SIGN_NOPS (base0); + if (TREE_CODE (base0) == ADDR_EXPR) + { + base0 + = get_inner_reference (TREE_OPERAND (base0, 0), + &bitsize, &bitpos0, &offset0, &mode, + &unsignedp, &reversep, &volatilep); + if (TREE_CODE (base0) == INDIRECT_REF) + base0 = TREE_OPERAND (base0, 0); + else + indirect_base0 = true; + } + if (offset0 == NULL_TREE || integer_zerop (offset0)) + offset0 = TREE_OPERAND (arg0, 1); + else + offset0 = size_binop (PLUS_EXPR, offset0, + TREE_OPERAND (arg0, 1)); + if (poly_int_tree_p (offset0)) + { + poly_offset_int tem = wi::sext (wi::to_poly_offset (offset0), + TYPE_PRECISION (sizetype)); + tem <<= LOG2_BITS_PER_UNIT; + tem += bitpos0; + if (tem.to_shwi (&bitpos0)) + offset0 = NULL_TREE; + } + } + + base1 = arg1; + if (TREE_CODE (arg1) == ADDR_EXPR) + { + base1 + = get_inner_reference (TREE_OPERAND (arg1, 0), + &bitsize, &bitpos1, &offset1, &mode, + &unsignedp, &reversep, &volatilep); + if (TREE_CODE (base1) == INDIRECT_REF) + base1 = TREE_OPERAND (base1, 0); + else + indirect_base1 = true; + } + else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR) + { + base1 = TREE_OPERAND (arg1, 0); + STRIP_SIGN_NOPS (base1); + if (TREE_CODE (base1) == ADDR_EXPR) + { + base1 + = get_inner_reference (TREE_OPERAND (base1, 0), + &bitsize, &bitpos1, &offset1, &mode, + &unsignedp, &reversep, &volatilep); + if (TREE_CODE (base1) == INDIRECT_REF) + base1 = TREE_OPERAND (base1, 0); + else + indirect_base1 = true; + } + if (offset1 == NULL_TREE || integer_zerop (offset1)) + offset1 = TREE_OPERAND (arg1, 1); + else + offset1 = size_binop (PLUS_EXPR, offset1, + TREE_OPERAND (arg1, 1)); + if (poly_int_tree_p (offset1)) + { + poly_offset_int tem = wi::sext (wi::to_poly_offset (offset1), + TYPE_PRECISION (sizetype)); + tem <<= LOG2_BITS_PER_UNIT; + tem += bitpos1; + if (tem.to_shwi (&bitpos1)) + offset1 = NULL_TREE; + } + } + + /* If we have equivalent bases we might be able to simplify. */ + if (indirect_base0 == indirect_base1 + && operand_equal_p (base0, base1, + indirect_base0 ? OEP_ADDRESS_OF : 0)) + { + /* We can fold this expression to a constant if the non-constant + offset parts are equal. */ + if ((offset0 == offset1 + || (offset0 && offset1 + && operand_equal_p (offset0, offset1, 0))) + && (equality_code + || (indirect_base0 + && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) + || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) + { + if (!equality_code + && maybe_ne (bitpos0, bitpos1) + && (pointer_may_wrap_p (base0, offset0, bitpos0) + || pointer_may_wrap_p (base1, offset1, bitpos1))) + fold_overflow_warning (("assuming pointer wraparound does not " + "occur when comparing P +- C1 with " + "P +- C2"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + + switch (code) + { + case EQ_EXPR: + if (known_eq (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_ne (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + case NE_EXPR: + if (known_ne (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_eq (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + case LT_EXPR: + if (known_lt (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_ge (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + case LE_EXPR: + if (known_le (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_gt (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + case GE_EXPR: + if (known_ge (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_lt (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + case GT_EXPR: + if (known_gt (bitpos0, bitpos1)) + return constant_boolean_node (true, type); + if (known_le (bitpos0, bitpos1)) + return constant_boolean_node (false, type); + break; + default:; + } + } + /* We can simplify the comparison to a comparison of the variable + offset parts if the constant offset parts are equal. + Be careful to use signed sizetype here because otherwise we + mess with array offsets in the wrong way. This is possible + because pointer arithmetic is restricted to retain within an + object and overflow on pointer differences is undefined as of + 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ + else if (known_eq (bitpos0, bitpos1) + && (equality_code + || (indirect_base0 + && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) + || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) + { + /* By converting to signed sizetype we cover middle-end pointer + arithmetic which operates on unsigned pointer types of size + type size and ARRAY_REF offsets which are properly sign or + zero extended from their type in case it is narrower than + sizetype. */ + if (offset0 == NULL_TREE) + offset0 = build_int_cst (ssizetype, 0); + else + offset0 = fold_convert_loc (loc, ssizetype, offset0); + if (offset1 == NULL_TREE) + offset1 = build_int_cst (ssizetype, 0); + else + offset1 = fold_convert_loc (loc, ssizetype, offset1); + + if (!equality_code + && (pointer_may_wrap_p (base0, offset0, bitpos0) + || pointer_may_wrap_p (base1, offset1, bitpos1))) + fold_overflow_warning (("assuming pointer wraparound does not " + "occur when comparing P +- C1 with " + "P +- C2"), + WARN_STRICT_OVERFLOW_COMPARISON); + + return fold_build2_loc (loc, code, type, offset0, offset1); + } + } + /* For equal offsets we can simplify to a comparison of the + base addresses. */ + else if (known_eq (bitpos0, bitpos1) + && (indirect_base0 + ? base0 != TREE_OPERAND (arg0, 0) : base0 != arg0) + && (indirect_base1 + ? base1 != TREE_OPERAND (arg1, 0) : base1 != arg1) + && ((offset0 == offset1) + || (offset0 && offset1 + && operand_equal_p (offset0, offset1, 0)))) + { + if (indirect_base0) + base0 = build_fold_addr_expr_loc (loc, base0); + if (indirect_base1) + base1 = build_fold_addr_expr_loc (loc, base1); + return fold_build2_loc (loc, code, type, base0, base1); + } + /* Comparison between an ordinary (non-weak) symbol and a null + pointer can be eliminated since such symbols must have a non + null address. In C, relational expressions between pointers + to objects and null pointers are undefined. The results + below follow the C++ rules with the additional property that + every object pointer compares greater than a null pointer. + */ + else if (((DECL_P (base0) + && maybe_nonzero_address (base0) > 0 + /* Avoid folding references to struct members at offset 0 to + prevent tests like '&ptr->firstmember == 0' from getting + eliminated. When ptr is null, although the -> expression + is strictly speaking invalid, GCC retains it as a matter + of QoI. See PR c/44555. */ + && (offset0 == NULL_TREE && known_ne (bitpos0, 0))) + || CONSTANT_CLASS_P (base0)) + && indirect_base0 + /* The caller guarantees that when one of the arguments is + constant (i.e., null in this case) it is second. */ + && integer_zerop (arg1)) + { + switch (code) + { + case EQ_EXPR: + case LE_EXPR: + case LT_EXPR: + return constant_boolean_node (false, type); + case GE_EXPR: + case GT_EXPR: + case NE_EXPR: + return constant_boolean_node (true, type); + default: + gcc_unreachable (); + } + } + } + + /* Transform comparisons of the form X +- C1 CMP Y +- C2 to + X CMP Y +- C2 +- C1 for signed X, Y. This is valid if + the resulting offset is smaller in absolute value than the + original one and has the same sign. */ + if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)) + && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))) + && (TREE_CODE (arg1) == PLUS_EXPR || TREE_CODE (arg1) == MINUS_EXPR) + && (TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST + && !TREE_OVERFLOW (TREE_OPERAND (arg1, 1)))) + { + tree const1 = TREE_OPERAND (arg0, 1); + tree const2 = TREE_OPERAND (arg1, 1); + tree variable1 = TREE_OPERAND (arg0, 0); + tree variable2 = TREE_OPERAND (arg1, 0); + tree cst; + const char * const warnmsg = G_("assuming signed overflow does not " + "occur when combining constants around " + "a comparison"); + + /* Put the constant on the side where it doesn't overflow and is + of lower absolute value and of same sign than before. */ + cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) + ? MINUS_EXPR : PLUS_EXPR, + const2, const1); + if (!TREE_OVERFLOW (cst) + && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2) + && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const2)) + { + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2_loc (loc, code, type, + variable1, + fold_build2_loc (loc, TREE_CODE (arg1), + TREE_TYPE (arg1), + variable2, cst)); + } + + cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) + ? MINUS_EXPR : PLUS_EXPR, + const1, const2); + if (!TREE_OVERFLOW (cst) + && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1) + && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const1)) + { + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2_loc (loc, code, type, + fold_build2_loc (loc, TREE_CODE (arg0), + TREE_TYPE (arg0), + variable1, cst), + variable2); + } + } + + tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1); + if (tem) + return tem; + + /* If we are comparing an expression that just has comparisons + of two integer values, arithmetic expressions of those comparisons, + and constants, we can simplify it. There are only three cases + to check: the two values can either be equal, the first can be + greater, or the second can be greater. Fold the expression for + those three values. Since each value must be 0 or 1, we have + eight possibilities, each of which corresponds to the constant 0 + or 1 or one of the six possible comparisons. + + This handles common cases like (a > b) == 0 but also handles + expressions like ((x > y) - (y > x)) > 0, which supposedly + occur in macroized code. */ + + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST) + { + tree cval1 = 0, cval2 = 0; + + if (twoval_comparison_p (arg0, &cval1, &cval2) + /* Don't handle degenerate cases here; they should already + have been handled anyway. */ + && cval1 != 0 && cval2 != 0 + && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2)) + && TREE_TYPE (cval1) == TREE_TYPE (cval2) + && INTEGRAL_TYPE_P (TREE_TYPE (cval1)) + && TYPE_MAX_VALUE (TREE_TYPE (cval1)) + && TYPE_MAX_VALUE (TREE_TYPE (cval2)) + && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)), + TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0)) + { + tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1)); + tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1)); + + /* We can't just pass T to eval_subst in case cval1 or cval2 + was the same as ARG1. */ + + tree high_result + = fold_build2_loc (loc, code, type, + eval_subst (loc, arg0, cval1, maxval, + cval2, minval), + arg1); + tree equal_result + = fold_build2_loc (loc, code, type, + eval_subst (loc, arg0, cval1, maxval, + cval2, maxval), + arg1); + tree low_result + = fold_build2_loc (loc, code, type, + eval_subst (loc, arg0, cval1, minval, + cval2, maxval), + arg1); + + /* All three of these results should be 0 or 1. Confirm they are. + Then use those values to select the proper code to use. */ + + if (TREE_CODE (high_result) == INTEGER_CST + && TREE_CODE (equal_result) == INTEGER_CST + && TREE_CODE (low_result) == INTEGER_CST) + { + /* Make a 3-bit mask with the high-order bit being the + value for `>', the next for '=', and the low for '<'. */ + switch ((integer_onep (high_result) * 4) + + (integer_onep (equal_result) * 2) + + integer_onep (low_result)) + { + case 0: + /* Always false. */ + return omit_one_operand_loc (loc, type, integer_zero_node, arg0); + case 1: + code = LT_EXPR; + break; + case 2: + code = EQ_EXPR; + break; + case 3: + code = LE_EXPR; + break; + case 4: + code = GT_EXPR; + break; + case 5: + code = NE_EXPR; + break; + case 6: + code = GE_EXPR; + break; + case 7: + /* Always true. */ + return omit_one_operand_loc (loc, type, integer_one_node, arg0); + } + + return fold_build2_loc (loc, code, type, cval1, cval2); + } + } + } + + return NULL_TREE; +} + + +/* Subroutine of fold_binary. Optimize complex multiplications of the + form z * conj(z), as pow(realpart(z),2) + pow(imagpart(z),2). The + argument EXPR represents the expression "z" of type TYPE. */ + +static tree +fold_mult_zconjz (location_t loc, tree type, tree expr) +{ + tree itype = TREE_TYPE (type); + tree rpart, ipart, tem; + + if (TREE_CODE (expr) == COMPLEX_EXPR) + { + rpart = TREE_OPERAND (expr, 0); + ipart = TREE_OPERAND (expr, 1); + } + else if (TREE_CODE (expr) == COMPLEX_CST) + { + rpart = TREE_REALPART (expr); + ipart = TREE_IMAGPART (expr); + } + else + { + expr = save_expr (expr); + rpart = fold_build1_loc (loc, REALPART_EXPR, itype, expr); + ipart = fold_build1_loc (loc, IMAGPART_EXPR, itype, expr); + } + + rpart = save_expr (rpart); + ipart = save_expr (ipart); + tem = fold_build2_loc (loc, PLUS_EXPR, itype, + fold_build2_loc (loc, MULT_EXPR, itype, rpart, rpart), + fold_build2_loc (loc, MULT_EXPR, itype, ipart, ipart)); + return fold_build2_loc (loc, COMPLEX_EXPR, type, tem, + build_zero_cst (itype)); +} + + +/* Helper function for fold_vec_perm. Store elements of VECTOR_CST or + CONSTRUCTOR ARG into array ELTS, which has NELTS elements, and return + true if successful. */ + +static bool +vec_cst_ctor_to_array (tree arg, unsigned int nelts, tree *elts) +{ + unsigned HOST_WIDE_INT i, nunits; + + if (TREE_CODE (arg) == VECTOR_CST + && VECTOR_CST_NELTS (arg).is_constant (&nunits)) + { + for (i = 0; i < nunits; ++i) + elts[i] = VECTOR_CST_ELT (arg, i); + } + else if (TREE_CODE (arg) == CONSTRUCTOR) + { + constructor_elt *elt; + + FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (arg), i, elt) + if (i >= nelts || TREE_CODE (TREE_TYPE (elt->value)) == VECTOR_TYPE) + return false; + else + elts[i] = elt->value; + } + else + return false; + for (; i < nelts; i++) + elts[i] + = fold_convert (TREE_TYPE (TREE_TYPE (arg)), integer_zero_node); + return true; +} + +/* Attempt to fold vector permutation of ARG0 and ARG1 vectors using SEL + selector. Return the folded VECTOR_CST or CONSTRUCTOR if successful, + NULL_TREE otherwise. */ + +tree +fold_vec_perm (tree type, tree arg0, tree arg1, const vec_perm_indices &sel) +{ + unsigned int i; + unsigned HOST_WIDE_INT nelts; + bool need_ctor = false; + + if (!sel.length ().is_constant (&nelts)) + return NULL_TREE; + gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (type), nelts) + && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), nelts) + && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)), nelts)); + if (TREE_TYPE (TREE_TYPE (arg0)) != TREE_TYPE (type) + || TREE_TYPE (TREE_TYPE (arg1)) != TREE_TYPE (type)) + return NULL_TREE; + + tree *in_elts = XALLOCAVEC (tree, nelts * 2); + if (!vec_cst_ctor_to_array (arg0, nelts, in_elts) + || !vec_cst_ctor_to_array (arg1, nelts, in_elts + nelts)) + return NULL_TREE; + + tree_vector_builder out_elts (type, nelts, 1); + for (i = 0; i < nelts; i++) + { + HOST_WIDE_INT index; + if (!sel[i].is_constant (&index)) + return NULL_TREE; + if (!CONSTANT_CLASS_P (in_elts[index])) + need_ctor = true; + out_elts.quick_push (unshare_expr (in_elts[index])); + } + + if (need_ctor) + { + vec<constructor_elt, va_gc> *v; + vec_alloc (v, nelts); + for (i = 0; i < nelts; i++) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, out_elts[i]); + return build_constructor (type, v); + } + else + return out_elts.build (); +} + +/* Try to fold a pointer difference of type TYPE two address expressions of + array references AREF0 and AREF1 using location LOC. Return a + simplified expression for the difference or NULL_TREE. */ + +static tree +fold_addr_of_array_ref_difference (location_t loc, tree type, + tree aref0, tree aref1, + bool use_pointer_diff) +{ + tree base0 = TREE_OPERAND (aref0, 0); + tree base1 = TREE_OPERAND (aref1, 0); + tree base_offset = build_int_cst (type, 0); + + /* If the bases are array references as well, recurse. If the bases + are pointer indirections compute the difference of the pointers. + If the bases are equal, we are set. */ + if ((TREE_CODE (base0) == ARRAY_REF + && TREE_CODE (base1) == ARRAY_REF + && (base_offset + = fold_addr_of_array_ref_difference (loc, type, base0, base1, + use_pointer_diff))) + || (INDIRECT_REF_P (base0) + && INDIRECT_REF_P (base1) + && (base_offset + = use_pointer_diff + ? fold_binary_loc (loc, POINTER_DIFF_EXPR, type, + TREE_OPERAND (base0, 0), + TREE_OPERAND (base1, 0)) + : fold_binary_loc (loc, MINUS_EXPR, type, + fold_convert (type, + TREE_OPERAND (base0, 0)), + fold_convert (type, + TREE_OPERAND (base1, 0))))) + || operand_equal_p (base0, base1, OEP_ADDRESS_OF)) + { + tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1)); + tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1)); + tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0)); + tree diff = fold_build2_loc (loc, MINUS_EXPR, type, op0, op1); + return fold_build2_loc (loc, PLUS_EXPR, type, + base_offset, + fold_build2_loc (loc, MULT_EXPR, type, + diff, esz)); + } + return NULL_TREE; +} + +/* If the real or vector real constant CST of type TYPE has an exact + inverse, return it, else return NULL. */ + +tree +exact_inverse (tree type, tree cst) +{ + REAL_VALUE_TYPE r; + tree unit_type; + machine_mode mode; + + switch (TREE_CODE (cst)) + { + case REAL_CST: + r = TREE_REAL_CST (cst); + + if (exact_real_inverse (TYPE_MODE (type), &r)) + return build_real (type, r); + + return NULL_TREE; + + case VECTOR_CST: + { + unit_type = TREE_TYPE (type); + mode = TYPE_MODE (unit_type); + + tree_vector_builder elts; + if (!elts.new_unary_operation (type, cst, false)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) + { + r = TREE_REAL_CST (VECTOR_CST_ELT (cst, i)); + if (!exact_real_inverse (mode, &r)) + return NULL_TREE; + elts.quick_push (build_real (unit_type, r)); + } + + return elts.build (); + } + + default: + return NULL_TREE; + } +} + +/* Mask out the tz least significant bits of X of type TYPE where + tz is the number of trailing zeroes in Y. */ +static wide_int +mask_with_tz (tree type, const wide_int &x, const wide_int &y) +{ + int tz = wi::ctz (y); + if (tz > 0) + return wi::mask (tz, true, TYPE_PRECISION (type)) & x; + return x; +} + +/* Return true when T is an address and is known to be nonzero. + For floating point we further ensure that T is not denormal. + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ + +static bool +tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p) +{ + tree type = TREE_TYPE (t); + enum tree_code code; + + /* Doing something useful for floating point would need more work. */ + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + return false; + + code = TREE_CODE (t); + switch (TREE_CODE_CLASS (code)) + { + case tcc_unary: + return tree_unary_nonzero_warnv_p (code, type, TREE_OPERAND (t, 0), + strict_overflow_p); + case tcc_binary: + case tcc_comparison: + return tree_binary_nonzero_warnv_p (code, type, + TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), + strict_overflow_p); + case tcc_constant: + case tcc_declaration: + case tcc_reference: + return tree_single_nonzero_warnv_p (t, strict_overflow_p); + + default: + break; + } + + switch (code) + { + case TRUTH_NOT_EXPR: + return tree_unary_nonzero_warnv_p (code, type, TREE_OPERAND (t, 0), + strict_overflow_p); + + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + return tree_binary_nonzero_warnv_p (code, type, + TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), + strict_overflow_p); + + case COND_EXPR: + case CONSTRUCTOR: + case OBJ_TYPE_REF: + case ASSERT_EXPR: + case ADDR_EXPR: + case WITH_SIZE_EXPR: + case SSA_NAME: + return tree_single_nonzero_warnv_p (t, strict_overflow_p); + + case COMPOUND_EXPR: + case MODIFY_EXPR: + case BIND_EXPR: + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p); + + case SAVE_EXPR: + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + + case CALL_EXPR: + { + tree fndecl = get_callee_fndecl (t); + if (!fndecl) return false; + if (flag_delete_null_pointer_checks && !flag_check_new + && DECL_IS_OPERATOR_NEW_P (fndecl) + && !TREE_NOTHROW (fndecl)) + return true; + if (flag_delete_null_pointer_checks + && lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + return true; + return alloca_call_p (t); + } + + default: + break; + } + return false; +} + +/* Return true when T is an address and is known to be nonzero. + Handle warnings about undefined signed overflow. */ + +bool +tree_expr_nonzero_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-zero"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + +/* Return true if T is known not to be equal to an integer W. */ + +bool +expr_not_equal_to (tree t, const wide_int &w) +{ + int_range_max vr; + switch (TREE_CODE (t)) + { + case INTEGER_CST: + return wi::to_wide (t) != w; + + case SSA_NAME: + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + return false; + + if (cfun) + get_range_query (cfun)->range_of_expr (vr, t); + else + get_global_range_query ()->range_of_expr (vr, t); + + if (!vr.undefined_p () + && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w))) + return true; + /* If T has some known zero bits and W has any of those bits set, + then T is known not to be equal to W. */ + if (wi::ne_p (wi::zext (wi::bit_and_not (w, get_nonzero_bits (t)), + TYPE_PRECISION (TREE_TYPE (t))), 0)) + return true; + return false; + + default: + return false; + } +} + +/* Fold a binary expression of code CODE and type TYPE with operands + OP0 and OP1. LOC is the location of the resulting expression. + Return the folded expression if folding is successful. Otherwise, + return NULL_TREE. */ + +tree +fold_binary_loc (location_t loc, enum tree_code code, tree type, + tree op0, tree op1) +{ + enum tree_code_class kind = TREE_CODE_CLASS (code); + tree arg0, arg1, tem; + tree t1 = NULL_TREE; + bool strict_overflow_p; + unsigned int prec; + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 2 + && op0 != NULL_TREE + && op1 != NULL_TREE); + + arg0 = op0; + arg1 = op1; + + /* Strip any conversions that don't change the mode. This is + safe for every expression, except for a comparison expression + because its signedness is derived from its operands. So, in + the latter case, only strip conversions that don't change the + signedness. MIN_EXPR/MAX_EXPR also need signedness of arguments + preserved. + + Note that this is done as an internal manipulation within the + constant folder, in order to find the simplest representation + of the arguments so that their form can be studied. In any + cases, the appropriate type conversions should be put back in + the tree that will get out of the constant folder. */ + + if (kind == tcc_comparison || code == MIN_EXPR || code == MAX_EXPR) + { + STRIP_SIGN_NOPS (arg0); + STRIP_SIGN_NOPS (arg1); + } + else + { + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + } + + /* Note that TREE_CONSTANT isn't enough: static var addresses are + constant but we can't do arithmetic on them. */ + if (CONSTANT_CLASS_P (arg0) && CONSTANT_CLASS_P (arg1)) + { + tem = const_binop (code, type, arg0, arg1); + if (tem != NULL_TREE) + { + if (TREE_TYPE (tem) != type) + tem = fold_convert_loc (loc, type, tem); + return tem; + } + } + + /* If this is a commutative operation, and ARG0 is a constant, move it + to ARG1 to reduce the number of tests below. */ + if (commutative_tree_code (code) + && tree_swap_operands_p (arg0, arg1)) + return fold_build2_loc (loc, code, type, op1, op0); + + /* Likewise if this is a comparison, and ARG0 is a constant, move it + to ARG1 to reduce the number of tests below. */ + if (kind == tcc_comparison + && tree_swap_operands_p (arg0, arg1)) + return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0); + + tem = generic_simplify (loc, code, type, op0, op1); + if (tem) + return tem; + + /* ARG0 is the first operand of EXPR, and ARG1 is the second operand. + + First check for cases where an arithmetic operation is applied to a + compound, conditional, or comparison operation. Push the arithmetic + operation inside the compound or conditional to see if any folding + can then be done. Convert comparison to conditional for this purpose. + The also optimizes non-constant cases that used to be done in + expand_expr. + + Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR, + one of the operands is a comparison and the other is a comparison, a + BIT_AND_EXPR with the constant 1, or a truth value. In that case, the + code below would make the expression more complex. Change it to a + TRUTH_{AND,OR}_EXPR. Likewise, convert a similar NE_EXPR to + TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR. */ + + if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR + || code == EQ_EXPR || code == NE_EXPR) + && !VECTOR_TYPE_P (TREE_TYPE (arg0)) + && ((truth_value_p (TREE_CODE (arg0)) + && (truth_value_p (TREE_CODE (arg1)) + || (TREE_CODE (arg1) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg1, 1))))) + || (truth_value_p (TREE_CODE (arg1)) + && (truth_value_p (TREE_CODE (arg0)) + || (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1))))))) + { + tem = fold_build2_loc (loc, code == BIT_AND_EXPR ? TRUTH_AND_EXPR + : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR + : TRUTH_XOR_EXPR, + boolean_type_node, + fold_convert_loc (loc, boolean_type_node, arg0), + fold_convert_loc (loc, boolean_type_node, arg1)); + + if (code == EQ_EXPR) + tem = invert_truthvalue_loc (loc, tem); + + return fold_convert_loc (loc, type, tem); + } + + if (TREE_CODE_CLASS (code) == tcc_binary + || TREE_CODE_CLASS (code) == tcc_comparison) + { + if (TREE_CODE (arg0) == COMPOUND_EXPR) + { + tem = fold_build2_loc (loc, code, type, + fold_convert_loc (loc, TREE_TYPE (op0), + TREE_OPERAND (arg0, 1)), op1); + return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), + tem); + } + if (TREE_CODE (arg1) == COMPOUND_EXPR) + { + tem = fold_build2_loc (loc, code, type, op0, + fold_convert_loc (loc, TREE_TYPE (op1), + TREE_OPERAND (arg1, 1))); + return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0), + tem); + } + + if (TREE_CODE (arg0) == COND_EXPR + || TREE_CODE (arg0) == VEC_COND_EXPR + || COMPARISON_CLASS_P (arg0)) + { + tem = fold_binary_op_with_conditional_arg (loc, code, type, op0, op1, + arg0, arg1, + /*cond_first_p=*/1); + if (tem != NULL_TREE) + return tem; + } + + if (TREE_CODE (arg1) == COND_EXPR + || TREE_CODE (arg1) == VEC_COND_EXPR + || COMPARISON_CLASS_P (arg1)) + { + tem = fold_binary_op_with_conditional_arg (loc, code, type, op0, op1, + arg1, arg0, + /*cond_first_p=*/0); + if (tem != NULL_TREE) + return tem; + } + } + + switch (code) + { + case MEM_REF: + /* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2]. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == MEM_REF) + { + tree iref = TREE_OPERAND (arg0, 0); + return fold_build2 (MEM_REF, type, + TREE_OPERAND (iref, 0), + int_const_binop (PLUS_EXPR, arg1, + TREE_OPERAND (iref, 1))); + } + + /* MEM[&a.b, CST2] -> MEM[&a, offsetof (a, b) + CST2]. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && handled_component_p (TREE_OPERAND (arg0, 0))) + { + tree base; + poly_int64 coffset; + base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0), + &coffset); + if (!base) + return NULL_TREE; + return fold_build2 (MEM_REF, type, + build1 (ADDR_EXPR, TREE_TYPE (arg0), base), + int_const_binop (PLUS_EXPR, arg1, + size_int (coffset))); + } + + return NULL_TREE; + + case POINTER_PLUS_EXPR: + /* INT +p INT -> (PTR)(INT + INT). Stripping types allows for this. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + && INTEGRAL_TYPE_P (TREE_TYPE (arg0))) + return fold_convert_loc (loc, type, + fold_build2_loc (loc, PLUS_EXPR, sizetype, + fold_convert_loc (loc, sizetype, + arg1), + fold_convert_loc (loc, sizetype, + arg0))); + + return NULL_TREE; + + case PLUS_EXPR: + if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type)) + { + /* X + (X / CST) * -CST is X % CST. */ + if (TREE_CODE (arg1) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR + && operand_equal_p (arg0, + TREE_OPERAND (TREE_OPERAND (arg1, 0), 0), 0)) + { + tree cst0 = TREE_OPERAND (TREE_OPERAND (arg1, 0), 1); + tree cst1 = TREE_OPERAND (arg1, 1); + tree sum = fold_binary_loc (loc, PLUS_EXPR, TREE_TYPE (cst1), + cst1, cst0); + if (sum && integer_zerop (sum)) + return fold_convert_loc (loc, type, + fold_build2_loc (loc, TRUNC_MOD_EXPR, + TREE_TYPE (arg0), arg0, + cst0)); + } + } + + /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the same or + one. Make sure the type is not saturating and has the signedness of + the stripped operands, as fold_plusminus_mult_expr will re-associate. + ??? The latter condition should use TYPE_OVERFLOW_* flags instead. */ + if ((TREE_CODE (arg0) == MULT_EXPR + || TREE_CODE (arg1) == MULT_EXPR) + && !TYPE_SATURATING (type) + && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg0)) + && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg1)) + && (!FLOAT_TYPE_P (type) || flag_associative_math)) + { + tree tem = fold_plusminus_mult_expr (loc, code, type, arg0, arg1); + if (tem) + return tem; + } + + if (! FLOAT_TYPE_P (type)) + { + /* Reassociate (plus (plus (mult) (foo)) (mult)) as + (plus (plus (mult) (mult)) (foo)) so that we can + take advantage of the factoring cases below. */ + if (ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_WRAPS (type) + && (((TREE_CODE (arg0) == PLUS_EXPR + || TREE_CODE (arg0) == MINUS_EXPR) + && TREE_CODE (arg1) == MULT_EXPR) + || ((TREE_CODE (arg1) == PLUS_EXPR + || TREE_CODE (arg1) == MINUS_EXPR) + && TREE_CODE (arg0) == MULT_EXPR))) + { + tree parg0, parg1, parg, marg; + enum tree_code pcode; + + if (TREE_CODE (arg1) == MULT_EXPR) + parg = arg0, marg = arg1; + else + parg = arg1, marg = arg0; + pcode = TREE_CODE (parg); + parg0 = TREE_OPERAND (parg, 0); + parg1 = TREE_OPERAND (parg, 1); + STRIP_NOPS (parg0); + STRIP_NOPS (parg1); + + if (TREE_CODE (parg0) == MULT_EXPR + && TREE_CODE (parg1) != MULT_EXPR) + return fold_build2_loc (loc, pcode, type, + fold_build2_loc (loc, PLUS_EXPR, type, + fold_convert_loc (loc, type, + parg0), + fold_convert_loc (loc, type, + marg)), + fold_convert_loc (loc, type, parg1)); + if (TREE_CODE (parg0) != MULT_EXPR + && TREE_CODE (parg1) == MULT_EXPR) + return + fold_build2_loc (loc, PLUS_EXPR, type, + fold_convert_loc (loc, type, parg0), + fold_build2_loc (loc, pcode, type, + fold_convert_loc (loc, type, marg), + fold_convert_loc (loc, type, + parg1))); + } + } + else + { + /* Fold __complex__ ( x, 0 ) + __complex__ ( 0, y ) + to __complex__ ( x, y ). This is not the same for SNaNs or + if signed zeros are involved. */ + if (!HONOR_SNANS (arg0) + && !HONOR_SIGNED_ZEROS (arg0) + && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))) + { + tree rtype = TREE_TYPE (TREE_TYPE (arg0)); + tree arg0r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg0); + tree arg0i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg0); + bool arg0rz = false, arg0iz = false; + if ((arg0r && (arg0rz = real_zerop (arg0r))) + || (arg0i && (arg0iz = real_zerop (arg0i)))) + { + tree arg1r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg1); + tree arg1i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg1); + if (arg0rz && arg1i && real_zerop (arg1i)) + { + tree rp = arg1r ? arg1r + : build1 (REALPART_EXPR, rtype, arg1); + tree ip = arg0i ? arg0i + : build1 (IMAGPART_EXPR, rtype, arg0); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); + } + else if (arg0iz && arg1r && real_zerop (arg1r)) + { + tree rp = arg0r ? arg0r + : build1 (REALPART_EXPR, rtype, arg0); + tree ip = arg1i ? arg1i + : build1 (IMAGPART_EXPR, rtype, arg1); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); + } + } + } + + /* Convert a + (b*c + d*e) into (a + b*c) + d*e. + We associate floats only if the user has specified + -fassociative-math. */ + if (flag_associative_math + && TREE_CODE (arg1) == PLUS_EXPR + && TREE_CODE (arg0) != MULT_EXPR) + { + tree tree10 = TREE_OPERAND (arg1, 0); + tree tree11 = TREE_OPERAND (arg1, 1); + if (TREE_CODE (tree11) == MULT_EXPR + && TREE_CODE (tree10) == MULT_EXPR) + { + tree tree0; + tree0 = fold_build2_loc (loc, PLUS_EXPR, type, arg0, tree10); + return fold_build2_loc (loc, PLUS_EXPR, type, tree0, tree11); + } + } + /* Convert (b*c + d*e) + a into b*c + (d*e +a). + We associate floats only if the user has specified + -fassociative-math. */ + if (flag_associative_math + && TREE_CODE (arg0) == PLUS_EXPR + && TREE_CODE (arg1) != MULT_EXPR) + { + tree tree00 = TREE_OPERAND (arg0, 0); + tree tree01 = TREE_OPERAND (arg0, 1); + if (TREE_CODE (tree01) == MULT_EXPR + && TREE_CODE (tree00) == MULT_EXPR) + { + tree tree0; + tree0 = fold_build2_loc (loc, PLUS_EXPR, type, tree01, arg1); + return fold_build2_loc (loc, PLUS_EXPR, type, tree00, tree0); + } + } + } + + bit_rotate: + /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A + is a rotate of A by C1 bits. */ + /* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A + is a rotate of A by B bits. + Similarly for (A << B) | (A >> (-B & C3)) where C3 is Z-1, + though in this case CODE must be | and not + or ^, otherwise + it doesn't return A when B is 0. */ + { + enum tree_code code0, code1; + tree rtype; + code0 = TREE_CODE (arg0); + code1 = TREE_CODE (arg1); + if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR) + || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR)) + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), 0) + && (rtype = TREE_TYPE (TREE_OPERAND (arg0, 0)), + TYPE_UNSIGNED (rtype)) + /* Only create rotates in complete modes. Other cases are not + expanded properly. */ + && (element_precision (rtype) + == GET_MODE_UNIT_PRECISION (TYPE_MODE (rtype)))) + { + tree tree01, tree11; + tree orig_tree01, orig_tree11; + enum tree_code code01, code11; + + tree01 = orig_tree01 = TREE_OPERAND (arg0, 1); + tree11 = orig_tree11 = TREE_OPERAND (arg1, 1); + STRIP_NOPS (tree01); + STRIP_NOPS (tree11); + code01 = TREE_CODE (tree01); + code11 = TREE_CODE (tree11); + if (code11 != MINUS_EXPR + && (code01 == MINUS_EXPR || code01 == BIT_AND_EXPR)) + { + std::swap (code0, code1); + std::swap (code01, code11); + std::swap (tree01, tree11); + std::swap (orig_tree01, orig_tree11); + } + if (code01 == INTEGER_CST + && code11 == INTEGER_CST + && (wi::to_widest (tree01) + wi::to_widest (tree11) + == element_precision (rtype))) + { + tem = build2_loc (loc, LROTATE_EXPR, + rtype, TREE_OPERAND (arg0, 0), + code0 == LSHIFT_EXPR + ? orig_tree01 : orig_tree11); + return fold_convert_loc (loc, type, tem); + } + else if (code11 == MINUS_EXPR) + { + tree tree110, tree111; + tree110 = TREE_OPERAND (tree11, 0); + tree111 = TREE_OPERAND (tree11, 1); + STRIP_NOPS (tree110); + STRIP_NOPS (tree111); + if (TREE_CODE (tree110) == INTEGER_CST + && compare_tree_int (tree110, + element_precision (rtype)) == 0 + && operand_equal_p (tree01, tree111, 0)) + { + tem = build2_loc (loc, (code0 == LSHIFT_EXPR + ? LROTATE_EXPR : RROTATE_EXPR), + rtype, TREE_OPERAND (arg0, 0), + orig_tree01); + return fold_convert_loc (loc, type, tem); + } + } + else if (code == BIT_IOR_EXPR + && code11 == BIT_AND_EXPR + && pow2p_hwi (element_precision (rtype))) + { + tree tree110, tree111; + tree110 = TREE_OPERAND (tree11, 0); + tree111 = TREE_OPERAND (tree11, 1); + STRIP_NOPS (tree110); + STRIP_NOPS (tree111); + if (TREE_CODE (tree110) == NEGATE_EXPR + && TREE_CODE (tree111) == INTEGER_CST + && compare_tree_int (tree111, + element_precision (rtype) - 1) == 0 + && operand_equal_p (tree01, TREE_OPERAND (tree110, 0), 0)) + { + tem = build2_loc (loc, (code0 == LSHIFT_EXPR + ? LROTATE_EXPR : RROTATE_EXPR), + rtype, TREE_OPERAND (arg0, 0), + orig_tree01); + return fold_convert_loc (loc, type, tem); + } + } + } + } + + associate: + /* In most languages, can't associate operations on floats through + parentheses. Rather than remember where the parentheses were, we + don't associate floats at all, unless the user has specified + -fassociative-math. + And, we need to make sure type is not saturating. */ + + if ((! FLOAT_TYPE_P (type) || flag_associative_math) + && !TYPE_SATURATING (type)) + { + tree var0, minus_var0, con0, minus_con0, lit0, minus_lit0; + tree var1, minus_var1, con1, minus_con1, lit1, minus_lit1; + tree atype = type; + bool ok = true; + + /* Split both trees into variables, constants, and literals. Then + associate each group together, the constants with literals, + then the result with variables. This increases the chances of + literals being recombined later and of generating relocatable + expressions for the sum of a constant and literal. */ + var0 = split_tree (arg0, type, code, + &minus_var0, &con0, &minus_con0, + &lit0, &minus_lit0, 0); + var1 = split_tree (arg1, type, code, + &minus_var1, &con1, &minus_con1, + &lit1, &minus_lit1, code == MINUS_EXPR); + + /* Recombine MINUS_EXPR operands by using PLUS_EXPR. */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + /* With undefined overflow prefer doing association in a type + which wraps on overflow, if that is one of the operand types. */ + if ((POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)) + && !TYPE_OVERFLOW_WRAPS (type)) + { + if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))) + atype = TREE_TYPE (arg0); + else if (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) + atype = TREE_TYPE (arg1); + gcc_assert (TYPE_PRECISION (atype) == TYPE_PRECISION (type)); + } + + /* With undefined overflow we can only associate constants with one + variable, and constants whose association doesn't overflow. */ + if ((POINTER_TYPE_P (atype) || INTEGRAL_TYPE_P (atype)) + && !TYPE_OVERFLOW_WRAPS (atype)) + { + if ((var0 && var1) || (minus_var0 && minus_var1)) + { + /* ??? If split_tree would handle NEGATE_EXPR we could + simply reject these cases and the allowed cases would + be the var0/minus_var1 ones. */ + tree tmp0 = var0 ? var0 : minus_var0; + tree tmp1 = var1 ? var1 : minus_var1; + bool one_neg = false; + + if (TREE_CODE (tmp0) == NEGATE_EXPR) + { + tmp0 = TREE_OPERAND (tmp0, 0); + one_neg = !one_neg; + } + if (CONVERT_EXPR_P (tmp0) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp0, 0))) + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp0, 0))) + <= TYPE_PRECISION (atype))) + tmp0 = TREE_OPERAND (tmp0, 0); + if (TREE_CODE (tmp1) == NEGATE_EXPR) + { + tmp1 = TREE_OPERAND (tmp1, 0); + one_neg = !one_neg; + } + if (CONVERT_EXPR_P (tmp1) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp1, 0))) + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp1, 0))) + <= TYPE_PRECISION (atype))) + tmp1 = TREE_OPERAND (tmp1, 0); + /* The only case we can still associate with two variables + is if they cancel out. */ + if (!one_neg + || !operand_equal_p (tmp0, tmp1, 0)) + ok = false; + } + else if ((var0 && minus_var1 + && ! operand_equal_p (var0, minus_var1, 0)) + || (minus_var0 && var1 + && ! operand_equal_p (minus_var0, var1, 0))) + ok = false; + } + + /* Only do something if we found more than two objects. Otherwise, + nothing has changed and we risk infinite recursion. */ + if (ok + && ((var0 != 0) + (var1 != 0) + + (minus_var0 != 0) + (minus_var1 != 0) + + (con0 != 0) + (con1 != 0) + + (minus_con0 != 0) + (minus_con1 != 0) + + (lit0 != 0) + (lit1 != 0) + + (minus_lit0 != 0) + (minus_lit1 != 0)) > 2) + { + var0 = associate_trees (loc, var0, var1, code, atype); + minus_var0 = associate_trees (loc, minus_var0, minus_var1, + code, atype); + con0 = associate_trees (loc, con0, con1, code, atype); + minus_con0 = associate_trees (loc, minus_con0, minus_con1, + code, atype); + lit0 = associate_trees (loc, lit0, lit1, code, atype); + minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1, + code, atype); + + if (minus_var0 && var0) + { + var0 = associate_trees (loc, var0, minus_var0, + MINUS_EXPR, atype); + minus_var0 = 0; + } + if (minus_con0 && con0) + { + con0 = associate_trees (loc, con0, minus_con0, + MINUS_EXPR, atype); + minus_con0 = 0; + } + + /* Preserve the MINUS_EXPR if the negative part of the literal is + greater than the positive part. Otherwise, the multiplicative + folding code (i.e extract_muldiv) may be fooled in case + unsigned constants are subtracted, like in the following + example: ((X*2 + 4) - 8U)/2. */ + if (minus_lit0 && lit0) + { + if (TREE_CODE (lit0) == INTEGER_CST + && TREE_CODE (minus_lit0) == INTEGER_CST + && tree_int_cst_lt (lit0, minus_lit0) + /* But avoid ending up with only negated parts. */ + && (var0 || con0)) + { + minus_lit0 = associate_trees (loc, minus_lit0, lit0, + MINUS_EXPR, atype); + lit0 = 0; + } + else + { + lit0 = associate_trees (loc, lit0, minus_lit0, + MINUS_EXPR, atype); + minus_lit0 = 0; + } + } + + /* Don't introduce overflows through reassociation. */ + if ((lit0 && TREE_OVERFLOW_P (lit0)) + || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0))) + return NULL_TREE; + + /* Eliminate lit0 and minus_lit0 to con0 and minus_con0. */ + con0 = associate_trees (loc, con0, lit0, code, atype); + lit0 = 0; + minus_con0 = associate_trees (loc, minus_con0, minus_lit0, + code, atype); + minus_lit0 = 0; + + /* Eliminate minus_con0. */ + if (minus_con0) + { + if (con0) + con0 = associate_trees (loc, con0, minus_con0, + MINUS_EXPR, atype); + else if (var0) + var0 = associate_trees (loc, var0, minus_con0, + MINUS_EXPR, atype); + else + gcc_unreachable (); + minus_con0 = 0; + } + + /* Eliminate minus_var0. */ + if (minus_var0) + { + if (con0) + con0 = associate_trees (loc, con0, minus_var0, + MINUS_EXPR, atype); + else + gcc_unreachable (); + minus_var0 = 0; + } + + return + fold_convert_loc (loc, type, associate_trees (loc, var0, con0, + code, atype)); + } + } + + return NULL_TREE; + + case POINTER_DIFF_EXPR: + case MINUS_EXPR: + /* Fold &a[i] - &a[j] to i-j. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF + && TREE_CODE (arg1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF) + { + tree tem = fold_addr_of_array_ref_difference (loc, type, + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), + code + == POINTER_DIFF_EXPR); + if (tem) + return tem; + } + + /* Further transformations are not for pointers. */ + if (code == POINTER_DIFF_EXPR) + return NULL_TREE; + + /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ + if (TREE_CODE (arg0) == NEGATE_EXPR + && negate_expr_p (op1) + /* If arg0 is e.g. unsigned int and type is int, then this could + introduce UB, because if A is INT_MIN at runtime, the original + expression can be well defined while the latter is not. + See PR83269. */ + && !(ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_UNDEFINED (type) + && ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) + return fold_build2_loc (loc, MINUS_EXPR, type, negate_expr (op1), + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 0))); + + /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to + __complex__ ( x, -y ). This is not the same for SNaNs or if + signed zeros are involved. */ + if (!HONOR_SNANS (arg0) + && !HONOR_SIGNED_ZEROS (arg0) + && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))) + { + tree rtype = TREE_TYPE (TREE_TYPE (arg0)); + tree arg0r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg0); + tree arg0i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg0); + bool arg0rz = false, arg0iz = false; + if ((arg0r && (arg0rz = real_zerop (arg0r))) + || (arg0i && (arg0iz = real_zerop (arg0i)))) + { + tree arg1r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg1); + tree arg1i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg1); + if (arg0rz && arg1i && real_zerop (arg1i)) + { + tree rp = fold_build1_loc (loc, NEGATE_EXPR, rtype, + arg1r ? arg1r + : build1 (REALPART_EXPR, rtype, arg1)); + tree ip = arg0i ? arg0i + : build1 (IMAGPART_EXPR, rtype, arg0); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); + } + else if (arg0iz && arg1r && real_zerop (arg1r)) + { + tree rp = arg0r ? arg0r + : build1 (REALPART_EXPR, rtype, arg0); + tree ip = fold_build1_loc (loc, NEGATE_EXPR, rtype, + arg1i ? arg1i + : build1 (IMAGPART_EXPR, rtype, arg1)); + return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); + } + } + } + + /* A - B -> A + (-B) if B is easily negatable. */ + if (negate_expr_p (op1) + && ! TYPE_OVERFLOW_SANITIZED (type) + && ((FLOAT_TYPE_P (type) + /* Avoid this transformation if B is a positive REAL_CST. */ + && (TREE_CODE (op1) != REAL_CST + || REAL_VALUE_NEGATIVE (TREE_REAL_CST (op1)))) + || INTEGRAL_TYPE_P (type))) + return fold_build2_loc (loc, PLUS_EXPR, type, + fold_convert_loc (loc, type, arg0), + negate_expr (op1)); + + /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or + one. Make sure the type is not saturating and has the signedness of + the stripped operands, as fold_plusminus_mult_expr will re-associate. + ??? The latter condition should use TYPE_OVERFLOW_* flags instead. */ + if ((TREE_CODE (arg0) == MULT_EXPR + || TREE_CODE (arg1) == MULT_EXPR) + && !TYPE_SATURATING (type) + && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg0)) + && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg1)) + && (!FLOAT_TYPE_P (type) || flag_associative_math)) + { + tree tem = fold_plusminus_mult_expr (loc, code, type, arg0, arg1); + if (tem) + return tem; + } + + goto associate; + + case MULT_EXPR: + if (! FLOAT_TYPE_P (type)) + { + /* Transform x * -C into -x * C if x is easily negatable. */ + if (TREE_CODE (op1) == INTEGER_CST + && tree_int_cst_sgn (op1) == -1 + && negate_expr_p (op0) + && negate_expr_p (op1) + && (tem = negate_expr (op1)) != op1 + && ! TREE_OVERFLOW (tem)) + return fold_build2_loc (loc, MULT_EXPR, type, + fold_convert_loc (loc, type, + negate_expr (op0)), tem); + + strict_overflow_p = false; + if (TREE_CODE (arg1) == INTEGER_CST + && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p)) != 0) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying " + "multiplication"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert_loc (loc, type, tem); + } + + /* Optimize z * conj(z) for integer complex numbers. */ + if (TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (loc, type, arg1); + if (TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (loc, type, arg0); + } + else + { + /* Fold z * +-I to __complex__ (-+__imag z, +-__real z). + This is not the same for NaNs or if signed zeros are + involved. */ + if (!HONOR_NANS (arg0) + && !HONOR_SIGNED_ZEROS (arg0) + && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)) + && TREE_CODE (arg1) == COMPLEX_CST + && real_zerop (TREE_REALPART (arg1))) + { + tree rtype = TREE_TYPE (TREE_TYPE (arg0)); + if (real_onep (TREE_IMAGPART (arg1))) + return + fold_build2_loc (loc, COMPLEX_EXPR, type, + negate_expr (fold_build1_loc (loc, IMAGPART_EXPR, + rtype, arg0)), + fold_build1_loc (loc, REALPART_EXPR, rtype, arg0)); + else if (real_minus_onep (TREE_IMAGPART (arg1))) + return + fold_build2_loc (loc, COMPLEX_EXPR, type, + fold_build1_loc (loc, IMAGPART_EXPR, rtype, arg0), + negate_expr (fold_build1_loc (loc, REALPART_EXPR, + rtype, arg0))); + } + + /* Optimize z * conj(z) for floating point complex numbers. + Guarded by flag_unsafe_math_optimizations as non-finite + imaginary components don't produce scalar results. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (loc, type, arg1); + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (loc, type, arg0); + } + goto associate; + + case BIT_IOR_EXPR: + /* Canonicalize (X & C1) | C2. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + int width = TYPE_PRECISION (type), w; + wide_int c1 = wi::to_wide (TREE_OPERAND (arg0, 1)); + wide_int c2 = wi::to_wide (arg1); + + /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */ + if ((c1 & c2) == c1) + return omit_one_operand_loc (loc, type, arg1, + TREE_OPERAND (arg0, 0)); + + wide_int msk = wi::mask (width, false, + TYPE_PRECISION (TREE_TYPE (arg1))); + + /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */ + if (wi::bit_and_not (msk, c1 | c2) == 0) + { + tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1); + } + + /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2, + unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some + mode which allows further optimizations. */ + c1 &= msk; + c2 &= msk; + wide_int c3 = wi::bit_and_not (c1, c2); + for (w = BITS_PER_UNIT; w <= width; w <<= 1) + { + wide_int mask = wi::mask (w, false, + TYPE_PRECISION (type)); + if (((c1 | c2) & mask) == mask + && wi::bit_and_not (c1, mask) == 0) + { + c3 = mask; + break; + } + } + + if (c3 != c1) + { + tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + tem = fold_build2_loc (loc, BIT_AND_EXPR, type, tem, + wide_int_to_tree (type, c3)); + return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1); + } + } + + /* See if this can be simplified into a rotate first. If that + is unsuccessful continue in the association code. */ + goto bit_rotate; + + case BIT_XOR_EXPR: + /* Fold (X & 1) ^ 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && INTEGRAL_TYPE_P (type) + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_onep (arg1)) + return fold_build2_loc (loc, EQ_EXPR, type, arg0, + build_zero_cst (TREE_TYPE (arg0))); + + /* See if this can be simplified into a rotate first. If that + is unsuccessful continue in the association code. */ + goto bit_rotate; + + case BIT_AND_EXPR: + /* Fold (X ^ 1) & 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && INTEGRAL_TYPE_P (type) + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_onep (arg1)) + { + tree tem2; + tem = TREE_OPERAND (arg0, 0); + tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1); + tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem), + tem, tem2); + return fold_build2_loc (loc, EQ_EXPR, type, tem2, + build_zero_cst (TREE_TYPE (tem))); + } + /* Fold ~X & 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && INTEGRAL_TYPE_P (type) + && integer_onep (arg1)) + { + tree tem2; + tem = TREE_OPERAND (arg0, 0); + tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1); + tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem), + tem, tem2); + return fold_build2_loc (loc, EQ_EXPR, type, tem2, + build_zero_cst (TREE_TYPE (tem))); + } + /* Fold !X & 1 as X == 0. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && integer_onep (arg1)) + { + tem = TREE_OPERAND (arg0, 0); + return fold_build2_loc (loc, EQ_EXPR, type, tem, + build_zero_cst (TREE_TYPE (tem))); + } + + /* Fold (X * Y) & -(1 << CST) to X * Y if Y is a constant + multiple of 1 << CST. */ + if (TREE_CODE (arg1) == INTEGER_CST) + { + wi::tree_to_wide_ref cst1 = wi::to_wide (arg1); + wide_int ncst1 = -cst1; + if ((cst1 & ncst1) == ncst1 + && multiple_of_p (type, arg0, + wide_int_to_tree (TREE_TYPE (arg1), ncst1))) + return fold_convert_loc (loc, type, arg0); + } + + /* Fold (X * CST1) & CST2 to zero if we can, or drop known zero + bits from CST2. */ + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + wi::tree_to_wide_ref warg1 = wi::to_wide (arg1); + wide_int masked + = mask_with_tz (type, warg1, wi::to_wide (TREE_OPERAND (arg0, 1))); + + if (masked == 0) + return omit_two_operands_loc (loc, type, build_zero_cst (type), + arg0, arg1); + else if (masked != warg1) + { + /* Avoid the transform if arg1 is a mask of some + mode which allows further optimizations. */ + int pop = wi::popcount (warg1); + if (!(pop >= BITS_PER_UNIT + && pow2p_hwi (pop) + && wi::mask (pop, false, warg1.get_precision ()) == warg1)) + return fold_build2_loc (loc, code, type, op0, + wide_int_to_tree (type, masked)); + } + } + + /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char. */ + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR + && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + prec = element_precision (TREE_TYPE (TREE_OPERAND (arg0, 0))); + + wide_int mask = wide_int::from (wi::to_wide (arg1), prec, UNSIGNED); + if (mask == -1) + return + fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + } + + goto associate; + + case RDIV_EXPR: + /* Don't touch a floating-point divide by zero unless the mode + of the constant can represent infinity. */ + if (TREE_CODE (arg1) == REAL_CST + && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))) + && real_zerop (arg1)) + return NULL_TREE; + + /* (-A) / (-B) -> A / B */ + if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) + return fold_build2_loc (loc, RDIV_EXPR, type, + TREE_OPERAND (arg0, 0), + negate_expr (arg1)); + if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) + return fold_build2_loc (loc, RDIV_EXPR, type, + negate_expr (arg0), + TREE_OPERAND (arg1, 0)); + return NULL_TREE; + + case TRUNC_DIV_EXPR: + /* Fall through */ + + case FLOOR_DIV_EXPR: + /* Simplify A / (B << N) where A and B are positive and B is + a power of 2, to A >> (N + log2(B)). */ + strict_overflow_p = false; + if (TREE_CODE (arg1) == LSHIFT_EXPR + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (op0, &strict_overflow_p))) + { + tree sval = TREE_OPERAND (arg1, 0); + if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0) + { + tree sh_cnt = TREE_OPERAND (arg1, 1); + tree pow2 = build_int_cst (TREE_TYPE (sh_cnt), + wi::exact_log2 (wi::to_wide (sval))); + + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying A / (B << N)"), + WARN_STRICT_OVERFLOW_MISC); + + sh_cnt = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (sh_cnt), + sh_cnt, pow2); + return fold_build2_loc (loc, RSHIFT_EXPR, type, + fold_convert_loc (loc, type, arg0), sh_cnt); + } + } + + /* Fall through */ + + case ROUND_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + if (integer_zerop (arg1)) + return NULL_TREE; + + /* Convert -A / -B to A / B when the type is signed and overflow is + undefined. */ + if ((!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + && TREE_CODE (op0) == NEGATE_EXPR + && negate_expr_p (op1)) + { + if (ANY_INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2_loc (loc, code, type, + fold_convert_loc (loc, type, + TREE_OPERAND (arg0, 0)), + negate_expr (op1)); + } + if ((!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + && TREE_CODE (arg1) == NEGATE_EXPR + && negate_expr_p (op0)) + { + if (ANY_INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2_loc (loc, code, type, + negate_expr (op0), + fold_convert_loc (loc, type, + TREE_OPERAND (arg1, 0))); + } + + /* If arg0 is a multiple of arg1, then rewrite to the fastest div + operation, EXACT_DIV_EXPR. + + Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now. + At one time others generated faster code, it's not clear if they do + after the last round to changes to the DIV code in expmed.c. */ + if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR) + && multiple_of_p (type, arg0, arg1)) + return fold_build2_loc (loc, EXACT_DIV_EXPR, type, + fold_convert (type, arg0), + fold_convert (type, arg1)); + + strict_overflow_p = false; + if (TREE_CODE (arg1) == INTEGER_CST + && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p)) != 0) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert_loc (loc, type, tem); + } + + return NULL_TREE; + + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case TRUNC_MOD_EXPR: + strict_overflow_p = false; + if (TREE_CODE (arg1) == INTEGER_CST + && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p)) != 0) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying modulus"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert_loc (loc, type, tem); + } + + return NULL_TREE; + + case LROTATE_EXPR: + case RROTATE_EXPR: + case RSHIFT_EXPR: + case LSHIFT_EXPR: + /* Since negative shift count is not well-defined, + don't try to compute it in the compiler. */ + if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0) + return NULL_TREE; + + prec = element_precision (type); + + /* If we have a rotate of a bit operation with the rotate count and + the second operand of the bit operation both constant, + permute the two operations. */ + if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST + && (TREE_CODE (arg0) == BIT_AND_EXPR + || TREE_CODE (arg0) == BIT_IOR_EXPR + || TREE_CODE (arg0) == BIT_XOR_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tree arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + tree arg01 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1)); + return fold_build2_loc (loc, TREE_CODE (arg0), type, + fold_build2_loc (loc, code, type, + arg00, arg1), + fold_build2_loc (loc, code, type, + arg01, arg1)); + } + + /* Two consecutive rotates adding up to the some integer + multiple of the precision of the type can be ignored. */ + if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) == RROTATE_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && wi::umod_trunc (wi::to_wide (arg1) + + wi::to_wide (TREE_OPERAND (arg0, 1)), + prec) == 0) + return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + + return NULL_TREE; + + case MIN_EXPR: + case MAX_EXPR: + goto associate; + + case TRUTH_ANDIF_EXPR: + /* Note that the operands of this must be ints + and their values must be 0 or 1. + ("true" is a fixed value perhaps depending on the language.) */ + /* If first arg is constant zero, return it. */ + if (integer_zerop (arg0)) + return fold_convert_loc (loc, type, arg0); + /* FALLTHRU */ + case TRUTH_AND_EXPR: + /* If either arg is constant true, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1) + /* Preserve sequence points. */ + && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); + /* If second arg is constant zero, result is zero, but first arg + must be evaluated. */ + if (integer_zerop (arg1)) + return omit_one_operand_loc (loc, type, arg1, arg0); + /* Likewise for first arg, but note that only the TRUTH_AND_EXPR + case will be handled here. */ + if (integer_zerop (arg0)) + return omit_one_operand_loc (loc, type, arg0, arg1); + + /* !X && X is always false. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand_loc (loc, type, integer_zero_node, arg1); + /* X && !X is always false. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand_loc (loc, type, integer_zero_node, arg0); + + /* A < X && A + 1 > Y ==> A < X && A >= Y. Normally A + 1 > Y + means A >= Y && A != MAX, but in this case we know that + A < X <= MAX. */ + + if (!TREE_SIDE_EFFECTS (arg0) + && !TREE_SIDE_EFFECTS (arg1)) + { + tem = fold_to_nonsharp_ineq_using_bound (loc, arg0, arg1); + if (tem && !operand_equal_p (tem, arg0, 0)) + return fold_build2_loc (loc, code, type, tem, arg1); + + tem = fold_to_nonsharp_ineq_using_bound (loc, arg1, arg0); + if (tem && !operand_equal_p (tem, arg1, 0)) + return fold_build2_loc (loc, code, type, arg0, tem); + } + + if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1)) + != NULL_TREE) + return tem; + + return NULL_TREE; + + case TRUTH_ORIF_EXPR: + /* Note that the operands of this must be ints + and their values must be 0 or true. + ("true" is a fixed value perhaps depending on the language.) */ + /* If first arg is constant true, return it. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return fold_convert_loc (loc, type, arg0); + /* FALLTHRU */ + case TRUTH_OR_EXPR: + /* If either arg is constant zero, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); + if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1) + /* Preserve sequence points. */ + && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); + /* If second arg is constant true, result is true, but we must + evaluate first arg. */ + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)) + return omit_one_operand_loc (loc, type, arg1, arg0); + /* Likewise for first arg, but note this only occurs here for + TRUTH_OR_EXPR. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return omit_one_operand_loc (loc, type, arg0, arg1); + + /* !X || X is always true. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand_loc (loc, type, integer_one_node, arg1); + /* X || !X is always true. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand_loc (loc, type, integer_one_node, arg0); + + /* (X && !Y) || (!X && Y) is X ^ Y */ + if (TREE_CODE (arg0) == TRUTH_AND_EXPR + && TREE_CODE (arg1) == TRUTH_AND_EXPR) + { + tree a0, a1, l0, l1, n0, n1; + + a0 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0)); + a1 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1)); + + l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1)); + + n0 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l0); + n1 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l1); + + if ((operand_equal_p (n0, a0, 0) + && operand_equal_p (n1, a1, 0)) + || (operand_equal_p (n0, a1, 0) + && operand_equal_p (n1, a0, 0))) + return fold_build2_loc (loc, TRUTH_XOR_EXPR, type, l0, n1); + } + + if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1)) + != NULL_TREE) + return tem; + + return NULL_TREE; + + case TRUTH_XOR_EXPR: + /* If the second arg is constant zero, drop it. */ + if (integer_zerop (arg1)) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); + /* If the second arg is constant true, this is a logical inversion. */ + if (integer_onep (arg1)) + { + tem = invert_truthvalue_loc (loc, arg0); + return non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); + } + /* Identical arguments cancel to zero. */ + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand_loc (loc, type, integer_zero_node, arg0); + + /* !X ^ X is always true. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand_loc (loc, type, integer_one_node, arg1); + + /* X ^ !X is always true. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand_loc (loc, type, integer_one_node, arg0); + + return NULL_TREE; + + case EQ_EXPR: + case NE_EXPR: + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + tem = fold_comparison (loc, code, type, op0, op1); + if (tem != NULL_TREE) + return tem; + + /* bool_var != 1 becomes !bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1) + && code == NE_EXPR) + return fold_convert_loc (loc, type, + fold_build1_loc (loc, TRUTH_NOT_EXPR, + TREE_TYPE (arg0), arg0)); + + /* bool_var == 0 becomes !bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1) + && code == EQ_EXPR) + return fold_convert_loc (loc, type, + fold_build1_loc (loc, TRUTH_NOT_EXPR, + TREE_TYPE (arg0), arg0)); + + /* !exp != 0 becomes !exp */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR && integer_zerop (arg1) + && code == NE_EXPR) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); + + /* If this is an EQ or NE comparison with zero and ARG0 is + (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require + two operations, but the latter can be done in one less insn + on machines that have only two-operand insns or on which a + constant cannot be the first operand. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_zerop (arg1)) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + if (TREE_CODE (arg00) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg00, 0))) + { + tree tem = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (arg00), + arg01, TREE_OPERAND (arg00, 1)); + tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), tem, + build_one_cst (TREE_TYPE (arg0))); + return fold_build2_loc (loc, code, type, + fold_convert_loc (loc, TREE_TYPE (arg1), + tem), arg1); + } + else if (TREE_CODE (arg01) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg01, 0))) + { + tree tem = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (arg01), + arg00, TREE_OPERAND (arg01, 1)); + tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), tem, + build_one_cst (TREE_TYPE (arg0))); + return fold_build2_loc (loc, code, type, + fold_convert_loc (loc, TREE_TYPE (arg1), + tem), arg1); + } + } + + /* Fold ((X >> C1) & C2) == 0 and ((X >> C1) & C2) != 0 where + C1 is a valid shift constant, and C2 is a power of two, i.e. + a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && integer_zerop (arg1)) + { + tree arg00 = TREE_OPERAND (arg0, 0); + STRIP_NOPS (arg00); + if (TREE_CODE (arg00) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (arg00, 1)) == INTEGER_CST) + { + tree itype = TREE_TYPE (arg00); + tree arg001 = TREE_OPERAND (arg00, 1); + prec = TYPE_PRECISION (itype); + + /* Check for a valid shift count. */ + if (wi::ltu_p (wi::to_wide (arg001), prec)) + { + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg000 = TREE_OPERAND (arg00, 0); + unsigned HOST_WIDE_INT log2 = tree_log2 (arg01); + /* If (C2 << C1) doesn't overflow, then + ((X >> C1) & C2) != 0 can be rewritten as + (X & (C2 << C1)) != 0. */ + if ((log2 + TREE_INT_CST_LOW (arg001)) < prec) + { + tem = fold_build2_loc (loc, LSHIFT_EXPR, itype, + arg01, arg001); + tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, + arg000, tem); + return fold_build2_loc (loc, code, type, tem, + fold_convert_loc (loc, itype, arg1)); + } + /* Otherwise, for signed (arithmetic) shifts, + ((X >> C1) & C2) != 0 is rewritten as X < 0, and + ((X >> C1) & C2) == 0 is rewritten as X >= 0. */ + else if (!TYPE_UNSIGNED (itype)) + return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR + : LT_EXPR, + type, arg000, + build_int_cst (itype, 0)); + /* Otherwise, of unsigned (logical) shifts, + ((X >> C1) & C2) != 0 is rewritten as (X,false), and + ((X >> C1) & C2) == 0 is rewritten as (X,true). */ + else + return omit_one_operand_loc (loc, type, + code == EQ_EXPR ? integer_one_node + : integer_zero_node, + arg000); + } + } + } + + /* If this is a comparison of a field, we may be able to simplify it. */ + if ((TREE_CODE (arg0) == COMPONENT_REF + || TREE_CODE (arg0) == BIT_FIELD_REF) + /* Handle the constant case even without -O + to make sure the warnings are given. */ + && (optimize || TREE_CODE (arg1) == INTEGER_CST)) + { + t1 = optimize_bit_field_compare (loc, code, type, arg0, arg1); + if (t1) + return t1; + } + + /* Optimize comparisons of strlen vs zero to a compare of the + first character of the string vs zero. To wit, + strlen(ptr) == 0 => *ptr == 0 + strlen(ptr) != 0 => *ptr != 0 + Other cases should reduce to one of these two (or a constant) + due to the return value of strlen being unsigned. */ + if (TREE_CODE (arg0) == CALL_EXPR && integer_zerop (arg1)) + { + tree fndecl = get_callee_fndecl (arg0); + + if (fndecl + && fndecl_built_in_p (fndecl, BUILT_IN_STRLEN) + && call_expr_nargs (arg0) == 1 + && (TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (arg0, 0))) + == POINTER_TYPE)) + { + tree ptrtype + = build_pointer_type (build_qualified_type (char_type_node, + TYPE_QUAL_CONST)); + tree ptr = fold_convert_loc (loc, ptrtype, + CALL_EXPR_ARG (arg0, 0)); + tree iref = build_fold_indirect_ref_loc (loc, ptr); + return fold_build2_loc (loc, code, type, iref, + build_int_cst (TREE_TYPE (iref), 0)); + } + } + + /* Fold (X >> C) != 0 into X < 0 if C is one less than the width + of X. Similarly fold (X >> C) == 0 into X >= 0. */ + if (TREE_CODE (arg0) == RSHIFT_EXPR + && integer_zerop (arg1) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + tree itype = TREE_TYPE (arg00); + if (wi::to_wide (arg01) == element_precision (itype) - 1) + { + if (TYPE_UNSIGNED (itype)) + { + itype = signed_type_for (itype); + arg00 = fold_convert_loc (loc, itype, arg00); + } + return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR : LT_EXPR, + type, arg00, build_zero_cst (itype)); + } + } + + /* Fold (~X & C) == 0 into (X & C) != 0 and (~X & C) != 0 into + (X & C) == 0 when C is a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_NOT_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), + TREE_OPERAND (TREE_OPERAND (arg0, 0), 0), + TREE_OPERAND (arg0, 1)); + return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, + type, tem, + fold_convert_loc (loc, TREE_TYPE (arg0), + arg1)); + } + + /* Fold ((X & C) ^ C) eq/ne 0 into (X & C) ne/eq 0, when the + constant C is a power of two, i.e. a single bit. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) + { + tree arg00 = TREE_OPERAND (arg0, 0); + return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, + arg00, build_int_cst (TREE_TYPE (arg00), 0)); + } + + /* Likewise, fold ((X ^ C) & C) eq/ne 0 into (X & C) ne/eq 0, + when is C is a power of two, i.e. a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_XOR_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) + { + tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg000), + arg000, TREE_OPERAND (arg0, 1)); + return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, + tem, build_int_cst (TREE_TYPE (tem), 0)); + } + + if (integer_zerop (arg1) + && tree_expr_nonzero_p (arg0)) + { + tree res = constant_boolean_node (code==NE_EXPR, type); + return omit_one_operand_loc (loc, type, res, arg0); + } + + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && TREE_CODE (arg1) == BIT_XOR_EXPR) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg10 = TREE_OPERAND (arg1, 0); + tree arg11 = TREE_OPERAND (arg1, 1); + tree itype = TREE_TYPE (arg0); + + /* Optimize (X ^ Z) op (Y ^ Z) as X op Y, and symmetries. + operand_equal_p guarantees no side-effects so we don't need + to use omit_one_operand on Z. */ + if (operand_equal_p (arg01, arg11, 0)) + return fold_build2_loc (loc, code, type, arg00, + fold_convert_loc (loc, TREE_TYPE (arg00), + arg10)); + if (operand_equal_p (arg01, arg10, 0)) + return fold_build2_loc (loc, code, type, arg00, + fold_convert_loc (loc, TREE_TYPE (arg00), + arg11)); + if (operand_equal_p (arg00, arg11, 0)) + return fold_build2_loc (loc, code, type, arg01, + fold_convert_loc (loc, TREE_TYPE (arg01), + arg10)); + if (operand_equal_p (arg00, arg10, 0)) + return fold_build2_loc (loc, code, type, arg01, + fold_convert_loc (loc, TREE_TYPE (arg01), + arg11)); + + /* Optimize (X ^ C1) op (Y ^ C2) as (X ^ (C1 ^ C2)) op Y. */ + if (TREE_CODE (arg01) == INTEGER_CST + && TREE_CODE (arg11) == INTEGER_CST) + { + tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, + fold_convert_loc (loc, itype, arg11)); + tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem); + return fold_build2_loc (loc, code, type, tem, + fold_convert_loc (loc, itype, arg10)); + } + } + + /* Attempt to simplify equality/inequality comparisons of complex + values. Only lower the comparison if the result is known or + can be simplified to a single scalar comparison. */ + if ((TREE_CODE (arg0) == COMPLEX_EXPR + || TREE_CODE (arg0) == COMPLEX_CST) + && (TREE_CODE (arg1) == COMPLEX_EXPR + || TREE_CODE (arg1) == COMPLEX_CST)) + { + tree real0, imag0, real1, imag1; + tree rcond, icond; + + if (TREE_CODE (arg0) == COMPLEX_EXPR) + { + real0 = TREE_OPERAND (arg0, 0); + imag0 = TREE_OPERAND (arg0, 1); + } + else + { + real0 = TREE_REALPART (arg0); + imag0 = TREE_IMAGPART (arg0); + } + + if (TREE_CODE (arg1) == COMPLEX_EXPR) + { + real1 = TREE_OPERAND (arg1, 0); + imag1 = TREE_OPERAND (arg1, 1); + } + else + { + real1 = TREE_REALPART (arg1); + imag1 = TREE_IMAGPART (arg1); + } + + rcond = fold_binary_loc (loc, code, type, real0, real1); + if (rcond && TREE_CODE (rcond) == INTEGER_CST) + { + if (integer_zerop (rcond)) + { + if (code == EQ_EXPR) + return omit_two_operands_loc (loc, type, boolean_false_node, + imag0, imag1); + return fold_build2_loc (loc, NE_EXPR, type, imag0, imag1); + } + else + { + if (code == NE_EXPR) + return omit_two_operands_loc (loc, type, boolean_true_node, + imag0, imag1); + return fold_build2_loc (loc, EQ_EXPR, type, imag0, imag1); + } + } + + icond = fold_binary_loc (loc, code, type, imag0, imag1); + if (icond && TREE_CODE (icond) == INTEGER_CST) + { + if (integer_zerop (icond)) + { + if (code == EQ_EXPR) + return omit_two_operands_loc (loc, type, boolean_false_node, + real0, real1); + return fold_build2_loc (loc, NE_EXPR, type, real0, real1); + } + else + { + if (code == NE_EXPR) + return omit_two_operands_loc (loc, type, boolean_true_node, + real0, real1); + return fold_build2_loc (loc, EQ_EXPR, type, real0, real1); + } + } + } + + return NULL_TREE; + + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + tem = fold_comparison (loc, code, type, op0, op1); + if (tem != NULL_TREE) + return tem; + + /* Transform comparisons of the form X +- C CMP X. */ + if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && !HONOR_SNANS (arg0)) + { + tree arg01 = TREE_OPERAND (arg0, 1); + enum tree_code code0 = TREE_CODE (arg0); + int is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1; + + /* (X - c) > X becomes false. */ + if (code == GT_EXPR + && ((code0 == MINUS_EXPR && is_positive >= 0) + || (code0 == PLUS_EXPR && is_positive <= 0))) + return constant_boolean_node (0, type); + + /* Likewise (X + c) < X becomes false. */ + if (code == LT_EXPR + && ((code0 == PLUS_EXPR && is_positive >= 0) + || (code0 == MINUS_EXPR && is_positive <= 0))) + return constant_boolean_node (0, type); + + /* Convert (X - c) <= X to true. */ + if (!HONOR_NANS (arg1) + && code == LE_EXPR + && ((code0 == MINUS_EXPR && is_positive >= 0) + || (code0 == PLUS_EXPR && is_positive <= 0))) + return constant_boolean_node (1, type); + + /* Convert (X + c) >= X to true. */ + if (!HONOR_NANS (arg1) + && code == GE_EXPR + && ((code0 == PLUS_EXPR && is_positive >= 0) + || (code0 == MINUS_EXPR && is_positive <= 0))) + return constant_boolean_node (1, type); + } + + /* If we are comparing an ABS_EXPR with a constant, we can + convert all the cases into explicit comparisons, but they may + well not be faster than doing the ABS and one comparison. + But ABS (X) <= C is a range comparison, which becomes a subtraction + and a comparison, and is probably faster. */ + if (code == LE_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) == ABS_EXPR + && ! TREE_SIDE_EFFECTS (arg0) + && (tem = negate_expr (arg1)) != 0 + && TREE_CODE (tem) == INTEGER_CST + && !TREE_OVERFLOW (tem)) + return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, + build2 (GE_EXPR, type, + TREE_OPERAND (arg0, 0), tem), + build2 (LE_EXPR, type, + TREE_OPERAND (arg0, 0), arg1)); + + /* Convert ABS_EXPR<x> >= 0 to true. */ + strict_overflow_p = false; + if (code == GE_EXPR + && (integer_zerop (arg1) + || (! HONOR_NANS (arg0) + && real_zerop (arg1))) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand_loc (loc, type, + constant_boolean_node (true, type), + arg0); + } + + /* Convert ABS_EXPR<x> < 0 to false. */ + strict_overflow_p = false; + if (code == LT_EXPR + && (integer_zerop (arg1) || real_zerop (arg1)) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand_loc (loc, type, + constant_boolean_node (false, type), + arg0); + } + + /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0 + and similarly for >= into !=. */ + if ((code == LT_EXPR || code == GE_EXPR) + && TYPE_UNSIGNED (TREE_TYPE (arg0)) + && TREE_CODE (arg1) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg1, 0))) + return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, + build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, + TREE_OPERAND (arg1, 1)), + build_zero_cst (TREE_TYPE (arg0))); + + /* Similarly for X < (cast) (1 << Y). But cast can't be narrowing, + otherwise Y might be >= # of bits in X's type and thus e.g. + (unsigned char) (1 << Y) for Y 15 might be 0. + If the cast is widening, then 1 << Y should have unsigned type, + otherwise if Y is number of bits in the signed shift type minus 1, + we can't optimize this. E.g. (unsigned long long) (1 << Y) for Y + 31 might be 0xffffffff80000000. */ + if ((code == LT_EXPR || code == GE_EXPR) + && (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + || VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg0))) + && TYPE_UNSIGNED (TREE_TYPE (arg0)) + && CONVERT_EXPR_P (arg1) + && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR + && (element_precision (TREE_TYPE (arg1)) + >= element_precision (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))) + || (element_precision (TREE_TYPE (arg1)) + == element_precision (TREE_TYPE (TREE_OPERAND (arg1, 0))))) + && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0))) + { + tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, + TREE_OPERAND (TREE_OPERAND (arg1, 0), 1)); + return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, + fold_convert_loc (loc, TREE_TYPE (arg0), tem), + build_zero_cst (TREE_TYPE (arg0))); + } + + return NULL_TREE; + + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case LTGT_EXPR: + /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */ + { + tree targ0 = strip_float_extensions (arg0); + tree targ1 = strip_float_extensions (arg1); + tree newtype = TREE_TYPE (targ0); + + if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype)) + newtype = TREE_TYPE (targ1); + + if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0))) + return fold_build2_loc (loc, code, type, + fold_convert_loc (loc, newtype, targ0), + fold_convert_loc (loc, newtype, targ1)); + } + + return NULL_TREE; + + case COMPOUND_EXPR: + /* When pedantic, a compound expression can be neither an lvalue + nor an integer constant expression. */ + if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1)) + return NULL_TREE; + /* Don't let (0, 0) be null pointer constant. */ + tem = integer_zerop (arg1) ? build1_loc (loc, NOP_EXPR, type, arg1) + : fold_convert_loc (loc, type, arg1); + return tem; + + case ASSERT_EXPR: + /* An ASSERT_EXPR should never be passed to fold_binary. */ + gcc_unreachable (); + + default: + return NULL_TREE; + } /* switch (code) */ +} + +/* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M, + ((A & N) + B) & M -> (A + B) & M + Similarly if (N & M) == 0, + ((A | N) + B) & M -> (A + B) & M + and for - instead of + (or unary - instead of +) + and/or ^ instead of |. + If B is constant and (B & M) == 0, fold into A & M. + + This function is a helper for match.pd patterns. Return non-NULL + type in which the simplified operation should be performed only + if any optimization is possible. + + ARG1 is M above, ARG00 is left operand of +/-, if CODE00 is BIT_*_EXPR, + then ARG00{0,1} are operands of that bitop, otherwise CODE00 is ERROR_MARK. + Similarly for ARG01, CODE01 and ARG01{0,1}, just for the right operand of + +/-. */ +tree +fold_bit_and_mask (tree type, tree arg1, enum tree_code code, + tree arg00, enum tree_code code00, tree arg000, tree arg001, + tree arg01, enum tree_code code01, tree arg010, tree arg011, + tree *pmop) +{ + gcc_assert (TREE_CODE (arg1) == INTEGER_CST); + gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR); + wi::tree_to_wide_ref cst1 = wi::to_wide (arg1); + if (~cst1 == 0 + || (cst1 & (cst1 + 1)) != 0 + || !INTEGRAL_TYPE_P (type) + || (!TYPE_OVERFLOW_WRAPS (type) + && TREE_CODE (type) != INTEGER_TYPE) + || (wi::max_value (type) & cst1) != cst1) + return NULL_TREE; + + enum tree_code codes[2] = { code00, code01 }; + tree arg0xx[4] = { arg000, arg001, arg010, arg011 }; + int which = 0; + wide_int cst0; + + /* Now we know that arg0 is (C + D) or (C - D) or -C and + arg1 (M) is == (1LL << cst) - 1. + Store C into PMOP[0] and D into PMOP[1]. */ + pmop[0] = arg00; + pmop[1] = arg01; + which = code != NEGATE_EXPR; + + for (; which >= 0; which--) + switch (codes[which]) + { + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + gcc_assert (TREE_CODE (arg0xx[2 * which + 1]) == INTEGER_CST); + cst0 = wi::to_wide (arg0xx[2 * which + 1]) & cst1; + if (codes[which] == BIT_AND_EXPR) + { + if (cst0 != cst1) + break; + } + else if (cst0 != 0) + break; + /* If C or D is of the form (A & N) where + (N & M) == M, or of the form (A | N) or + (A ^ N) where (N & M) == 0, replace it with A. */ + pmop[which] = arg0xx[2 * which]; + break; + case ERROR_MARK: + if (TREE_CODE (pmop[which]) != INTEGER_CST) + break; + /* If C or D is a N where (N & M) == 0, it can be + omitted (replaced with 0). */ + if ((code == PLUS_EXPR + || (code == MINUS_EXPR && which == 0)) + && (cst1 & wi::to_wide (pmop[which])) == 0) + pmop[which] = build_int_cst (type, 0); + /* Similarly, with C - N where (-N & M) == 0. */ + if (code == MINUS_EXPR + && which == 1 + && (cst1 & -wi::to_wide (pmop[which])) == 0) + pmop[which] = build_int_cst (type, 0); + break; + default: + gcc_unreachable (); + } + + /* Only build anything new if we optimized one or both arguments above. */ + if (pmop[0] == arg00 && pmop[1] == arg01) + return NULL_TREE; + + if (TYPE_OVERFLOW_WRAPS (type)) + return type; + else + return unsigned_type_for (type); +} + +/* Used by contains_label_[p1]. */ + +struct contains_label_data +{ + hash_set<tree> *pset; + bool inside_switch_p; +}; + +/* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is + a LABEL_EXPR or CASE_LABEL_EXPR not inside of another SWITCH_EXPR; otherwise + return NULL_TREE. Do not check the subtrees of GOTO_EXPR. */ + +static tree +contains_label_1 (tree *tp, int *walk_subtrees, void *data) +{ + contains_label_data *d = (contains_label_data *) data; + switch (TREE_CODE (*tp)) + { + case LABEL_EXPR: + return *tp; + + case CASE_LABEL_EXPR: + if (!d->inside_switch_p) + return *tp; + return NULL_TREE; + + case SWITCH_EXPR: + if (!d->inside_switch_p) + { + if (walk_tree (&SWITCH_COND (*tp), contains_label_1, data, d->pset)) + return *tp; + d->inside_switch_p = true; + if (walk_tree (&SWITCH_BODY (*tp), contains_label_1, data, d->pset)) + return *tp; + d->inside_switch_p = false; + *walk_subtrees = 0; + } + return NULL_TREE; + + case GOTO_EXPR: + *walk_subtrees = 0; + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* Return whether the sub-tree ST contains a label which is accessible from + outside the sub-tree. */ + +static bool +contains_label_p (tree st) +{ + hash_set<tree> pset; + contains_label_data data = { &pset, false }; + return walk_tree (&st, contains_label_1, &data, &pset) != NULL_TREE; +} + +/* Fold a ternary expression of code CODE and type TYPE with operands + OP0, OP1, and OP2. Return the folded expression if folding is + successful. Otherwise, return NULL_TREE. */ + +tree +fold_ternary_loc (location_t loc, enum tree_code code, tree type, + tree op0, tree op1, tree op2) +{ + tree tem; + tree arg0 = NULL_TREE, arg1 = NULL_TREE, arg2 = NULL_TREE; + enum tree_code_class kind = TREE_CODE_CLASS (code); + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 3); + + /* If this is a commutative operation, and OP0 is a constant, move it + to OP1 to reduce the number of tests below. */ + if (commutative_ternary_tree_code (code) + && tree_swap_operands_p (op0, op1)) + return fold_build3_loc (loc, code, type, op1, op0, op2); + + tem = generic_simplify (loc, code, type, op0, op1, op2); + if (tem) + return tem; + + /* Strip any conversions that don't change the mode. This is safe + for every expression, except for a comparison expression because + its signedness is derived from its operands. So, in the latter + case, only strip conversions that don't change the signedness. + + Note that this is done as an internal manipulation within the + constant folder, in order to find the simplest representation of + the arguments so that their form can be studied. In any cases, + the appropriate type conversions should be put back in the tree + that will get out of the constant folder. */ + if (op0) + { + arg0 = op0; + STRIP_NOPS (arg0); + } + + if (op1) + { + arg1 = op1; + STRIP_NOPS (arg1); + } + + if (op2) + { + arg2 = op2; + STRIP_NOPS (arg2); + } + + switch (code) + { + case COMPONENT_REF: + if (TREE_CODE (arg0) == CONSTRUCTOR + && ! type_contains_placeholder_p (TREE_TYPE (arg0))) + { + unsigned HOST_WIDE_INT idx; + tree field, value; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field, value) + if (field == arg1) + return value; + } + return NULL_TREE; + + case COND_EXPR: + case VEC_COND_EXPR: + /* Pedantic ANSI C says that a conditional expression is never an lvalue, + so all simple results must be passed through pedantic_non_lvalue. */ + if (TREE_CODE (arg0) == INTEGER_CST) + { + tree unused_op = integer_zerop (arg0) ? op1 : op2; + tem = integer_zerop (arg0) ? op2 : op1; + /* Only optimize constant conditions when the selected branch + has the same type as the COND_EXPR. This avoids optimizing + away "c ? x : throw", where the throw has a void type. + Avoid throwing away that operand which contains label. */ + if ((!TREE_SIDE_EFFECTS (unused_op) + || !contains_label_p (unused_op)) + && (! VOID_TYPE_P (TREE_TYPE (tem)) + || VOID_TYPE_P (type))) + return protected_set_expr_location_unshare (tem, loc); + return NULL_TREE; + } + else if (TREE_CODE (arg0) == VECTOR_CST) + { + unsigned HOST_WIDE_INT nelts; + if ((TREE_CODE (arg1) == VECTOR_CST + || TREE_CODE (arg1) == CONSTRUCTOR) + && (TREE_CODE (arg2) == VECTOR_CST + || TREE_CODE (arg2) == CONSTRUCTOR) + && TYPE_VECTOR_SUBPARTS (type).is_constant (&nelts)) + { + vec_perm_builder sel (nelts, nelts, 1); + for (unsigned int i = 0; i < nelts; i++) + { + tree val = VECTOR_CST_ELT (arg0, i); + if (integer_all_onesp (val)) + sel.quick_push (i); + else if (integer_zerop (val)) + sel.quick_push (nelts + i); + else /* Currently unreachable. */ + return NULL_TREE; + } + vec_perm_indices indices (sel, 2, nelts); + tree t = fold_vec_perm (type, arg1, arg2, indices); + if (t != NULL_TREE) + return t; + } + } + + /* If we have A op B ? A : C, we may be able to convert this to a + simpler expression, depending on the operation and the values + of B and C. Signed zeros prevent all of these transformations, + for reasons given above each one. + + Also try swapping the arguments and inverting the conditional. */ + if (COMPARISON_CLASS_P (arg0) + && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), op1) + && !HONOR_SIGNED_ZEROS (op1)) + { + tem = fold_cond_expr_with_comparison (loc, type, TREE_CODE (arg0), + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1), + op1, op2); + if (tem) + return tem; + } + + if (COMPARISON_CLASS_P (arg0) + && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), op2) + && !HONOR_SIGNED_ZEROS (op2)) + { + enum tree_code comp_code = TREE_CODE (arg0); + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + comp_code = invert_tree_comparison (comp_code, HONOR_NANS (arg00)); + if (comp_code != ERROR_MARK) + tem = fold_cond_expr_with_comparison (loc, type, comp_code, + arg00, + arg01, + op2, op1); + if (tem) + return tem; + } + + /* If the second operand is simpler than the third, swap them + since that produces better jump optimization results. */ + if (truth_value_p (TREE_CODE (arg0)) + && tree_swap_operands_p (op1, op2)) + { + location_t loc0 = expr_location_or (arg0, loc); + /* See if this can be inverted. If it can't, possibly because + it was a floating-point inequality comparison, don't do + anything. */ + tem = fold_invert_truthvalue (loc0, arg0); + if (tem) + return fold_build3_loc (loc, code, type, tem, op2, op1); + } + + /* Convert A ? 1 : 0 to simply A. */ + if ((code == VEC_COND_EXPR ? integer_all_onesp (op1) + : (integer_onep (op1) + && !VECTOR_TYPE_P (type))) + && integer_zerop (op2) + /* If we try to convert OP0 to our type, the + call to fold will try to move the conversion inside + a COND, which will recurse. In that case, the COND_EXPR + is probably the best choice, so leave it alone. */ + && type == TREE_TYPE (arg0)) + return protected_set_expr_location_unshare (arg0, loc); + + /* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR + over COND_EXPR in cases such as floating point comparisons. */ + if (integer_zerop (op1) + && code == COND_EXPR + && integer_onep (op2) + && !VECTOR_TYPE_P (type) + && truth_value_p (TREE_CODE (arg0))) + return fold_convert_loc (loc, type, + invert_truthvalue_loc (loc, arg0)); + + /* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>). */ + if (TREE_CODE (arg0) == LT_EXPR + && integer_zerop (TREE_OPERAND (arg0, 1)) + && integer_zerop (op2) + && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1))) + { + /* sign_bit_p looks through both zero and sign extensions, + but for this optimization only sign extensions are + usable. */ + tree tem2 = TREE_OPERAND (arg0, 0); + while (tem != tem2) + { + if (TREE_CODE (tem2) != NOP_EXPR + || TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (tem2, 0)))) + { + tem = NULL_TREE; + break; + } + tem2 = TREE_OPERAND (tem2, 0); + } + /* sign_bit_p only checks ARG1 bits within A's precision. + If <sign bit of A> has wider type than A, bits outside + of A's precision in <sign bit of A> need to be checked. + If they are all 0, this optimization needs to be done + in unsigned A's type, if they are all 1 in signed A's type, + otherwise this can't be done. */ + if (tem + && TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (TREE_TYPE (arg1)) + && TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (type)) + { + int inner_width, outer_width; + tree tem_type; + + inner_width = TYPE_PRECISION (TREE_TYPE (tem)); + outer_width = TYPE_PRECISION (TREE_TYPE (arg1)); + if (outer_width > TYPE_PRECISION (type)) + outer_width = TYPE_PRECISION (type); + + wide_int mask = wi::shifted_mask + (inner_width, outer_width - inner_width, false, + TYPE_PRECISION (TREE_TYPE (arg1))); + + wide_int common = mask & wi::to_wide (arg1); + if (common == mask) + { + tem_type = signed_type_for (TREE_TYPE (tem)); + tem = fold_convert_loc (loc, tem_type, tem); + } + else if (common == 0) + { + tem_type = unsigned_type_for (TREE_TYPE (tem)); + tem = fold_convert_loc (loc, tem_type, tem); + } + else + tem = NULL; + } + + if (tem) + return + fold_convert_loc (loc, type, + fold_build2_loc (loc, BIT_AND_EXPR, + TREE_TYPE (tem), tem, + fold_convert_loc (loc, + TREE_TYPE (tem), + arg1))); + } + + /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N). A & 1 was + already handled above. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_zerop (op2) + && integer_pow2p (arg1)) + { + tree tem = TREE_OPERAND (arg0, 0); + STRIP_NOPS (tem); + if (TREE_CODE (tem) == RSHIFT_EXPR + && tree_fits_uhwi_p (TREE_OPERAND (tem, 1)) + && (unsigned HOST_WIDE_INT) tree_log2 (arg1) + == tree_to_uhwi (TREE_OPERAND (tem, 1))) + return fold_build2_loc (loc, BIT_AND_EXPR, type, + fold_convert_loc (loc, type, + TREE_OPERAND (tem, 0)), + op1); + } + + /* A & N ? N : 0 is simply A & N if N is a power of two. This + is probably obsolete because the first operand should be a + truth value (that's why we have the two cases above), but let's + leave it in until we can confirm this for all front-ends. */ + if (integer_zerop (op2) + && TREE_CODE (arg0) == NE_EXPR + && integer_zerop (TREE_OPERAND (arg0, 1)) + && integer_pow2p (arg1) + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + arg1, OEP_ONLY_CONST) + /* operand_equal_p compares just value, not precision, so e.g. + arg1 could be 8-bit -128 and be power of two, but BIT_AND_EXPR + second operand 32-bit -128, which is not a power of two (or vice + versa. */ + && integer_pow2p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1))) + return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); + + /* Disable the transformations below for vectors, since + fold_binary_op_with_conditional_arg may undo them immediately, + yielding an infinite loop. */ + if (code == VEC_COND_EXPR) + return NULL_TREE; + + /* Convert A ? B : 0 into A && B if A and B are truth values. */ + if (integer_zerop (op2) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (arg1)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR + : TRUTH_ANDIF_EXPR, + type, fold_convert_loc (loc, type, arg0), op1); + + /* Convert A ? B : 1 into !A || B if A and B are truth values. */ + if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (arg1)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + { + location_t loc0 = expr_location_or (arg0, loc); + /* Only perform transformation if ARG0 is easily inverted. */ + tem = fold_invert_truthvalue (loc0, arg0); + if (tem) + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_IOR_EXPR + : TRUTH_ORIF_EXPR, + type, fold_convert_loc (loc, type, tem), + op1); + } + + /* Convert A ? 0 : B into !A && B if A and B are truth values. */ + if (integer_zerop (arg1) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (op2)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + { + location_t loc0 = expr_location_or (arg0, loc); + /* Only perform transformation if ARG0 is easily inverted. */ + tem = fold_invert_truthvalue (loc0, arg0); + if (tem) + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_AND_EXPR : TRUTH_ANDIF_EXPR, + type, fold_convert_loc (loc, type, tem), + op2); + } + + /* Convert A ? 1 : B into A || B if A and B are truth values. */ + if (code == VEC_COND_EXPR ? integer_all_onesp (arg1) : integer_onep (arg1) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (op2)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_IOR_EXPR : TRUTH_ORIF_EXPR, + type, fold_convert_loc (loc, type, arg0), op2); + + return NULL_TREE; + + case CALL_EXPR: + /* CALL_EXPRs used to be ternary exprs. Catch any mistaken uses + of fold_ternary on them. */ + gcc_unreachable (); + + case BIT_FIELD_REF: + if (TREE_CODE (arg0) == VECTOR_CST + && (type == TREE_TYPE (TREE_TYPE (arg0)) + || (VECTOR_TYPE_P (type) + && TREE_TYPE (type) == TREE_TYPE (TREE_TYPE (arg0)))) + && tree_fits_uhwi_p (op1) + && tree_fits_uhwi_p (op2)) + { + tree eltype = TREE_TYPE (TREE_TYPE (arg0)); + unsigned HOST_WIDE_INT width + = (TREE_CODE (eltype) == BOOLEAN_TYPE + ? TYPE_PRECISION (eltype) : tree_to_uhwi (TYPE_SIZE (eltype))); + unsigned HOST_WIDE_INT n = tree_to_uhwi (arg1); + unsigned HOST_WIDE_INT idx = tree_to_uhwi (op2); + + if (n != 0 + && (idx % width) == 0 + && (n % width) == 0 + && known_le ((idx + n) / width, + TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))) + { + idx = idx / width; + n = n / width; + + if (TREE_CODE (arg0) == VECTOR_CST) + { + if (n == 1) + { + tem = VECTOR_CST_ELT (arg0, idx); + if (VECTOR_TYPE_P (type)) + tem = fold_build1 (VIEW_CONVERT_EXPR, type, tem); + return tem; + } + + tree_vector_builder vals (type, n, 1); + for (unsigned i = 0; i < n; ++i) + vals.quick_push (VECTOR_CST_ELT (arg0, idx + i)); + return vals.build (); + } + } + } + + /* On constants we can use native encode/interpret to constant + fold (nearly) all BIT_FIELD_REFs. */ + if (CONSTANT_CLASS_P (arg0) + && can_native_interpret_type_p (type) + && BITS_PER_UNIT == 8 + && tree_fits_uhwi_p (op1) + && tree_fits_uhwi_p (op2)) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); + unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (op1); + /* Limit us to a reasonable amount of work. To relax the + other limitations we need bit-shifting of the buffer + and rounding up the size. */ + if (bitpos % BITS_PER_UNIT == 0 + && bitsize % BITS_PER_UNIT == 0 + && bitsize <= MAX_BITSIZE_MODE_ANY_MODE) + { + unsigned char b[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; + unsigned HOST_WIDE_INT len + = native_encode_expr (arg0, b, bitsize / BITS_PER_UNIT, + bitpos / BITS_PER_UNIT); + if (len > 0 + && len * BITS_PER_UNIT >= bitsize) + { + tree v = native_interpret_expr (type, b, + bitsize / BITS_PER_UNIT); + if (v) + return v; + } + } + } + + return NULL_TREE; + + case VEC_PERM_EXPR: + /* Perform constant folding of BIT_INSERT_EXPR. */ + if (TREE_CODE (arg2) == VECTOR_CST + && TREE_CODE (op0) == VECTOR_CST + && TREE_CODE (op1) == VECTOR_CST) + { + /* Build a vector of integers from the tree mask. */ + vec_perm_builder builder; + if (!tree_to_vec_perm_builder (&builder, arg2)) + return NULL_TREE; + + /* Create a vec_perm_indices for the integer vector. */ + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type); + bool single_arg = (op0 == op1); + vec_perm_indices sel (builder, single_arg ? 1 : 2, nelts); + return fold_vec_perm (type, op0, op1, sel); + } + return NULL_TREE; + + case BIT_INSERT_EXPR: + /* Perform (partial) constant folding of BIT_INSERT_EXPR. */ + if (TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) == INTEGER_CST) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); + unsigned bitsize = TYPE_PRECISION (TREE_TYPE (arg1)); + wide_int tem = (wi::to_wide (arg0) + & wi::shifted_mask (bitpos, bitsize, true, + TYPE_PRECISION (type))); + wide_int tem2 + = wi::lshift (wi::zext (wi::to_wide (arg1, TYPE_PRECISION (type)), + bitsize), bitpos); + return wide_int_to_tree (type, wi::bit_or (tem, tem2)); + } + else if (TREE_CODE (arg0) == VECTOR_CST + && CONSTANT_CLASS_P (arg1) + && types_compatible_p (TREE_TYPE (TREE_TYPE (arg0)), + TREE_TYPE (arg1))) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); + unsigned HOST_WIDE_INT elsize + = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg1))); + if (bitpos % elsize == 0) + { + unsigned k = bitpos / elsize; + unsigned HOST_WIDE_INT nelts; + if (operand_equal_p (VECTOR_CST_ELT (arg0, k), arg1, 0)) + return arg0; + else if (VECTOR_CST_NELTS (arg0).is_constant (&nelts)) + { + tree_vector_builder elts (type, nelts, 1); + elts.quick_grow (nelts); + for (unsigned HOST_WIDE_INT i = 0; i < nelts; ++i) + elts[i] = (i == k ? arg1 : VECTOR_CST_ELT (arg0, i)); + return elts.build (); + } + } + } + return NULL_TREE; + + default: + return NULL_TREE; + } /* switch (code) */ +} + +/* Gets the element ACCESS_INDEX from CTOR, which must be a CONSTRUCTOR + of an array (or vector). *CTOR_IDX if non-NULL is updated with the + constructor element index of the value returned. If the element is + not found NULL_TREE is returned and *CTOR_IDX is updated to + the index of the element after the ACCESS_INDEX position (which + may be outside of the CTOR array). */ + +tree +get_array_ctor_element_at_index (tree ctor, offset_int access_index, + unsigned *ctor_idx) +{ + tree index_type = NULL_TREE; + signop index_sgn = UNSIGNED; + offset_int low_bound = 0; + + if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE) + { + tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor)); + if (domain_type && TYPE_MIN_VALUE (domain_type)) + { + /* Static constructors for variably sized objects makes no sense. */ + gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST); + index_type = TREE_TYPE (TYPE_MIN_VALUE (domain_type)); + /* ??? When it is obvious that the range is signed, treat it so. */ + if (TYPE_UNSIGNED (index_type) + && TYPE_MAX_VALUE (domain_type) + && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), + TYPE_MIN_VALUE (domain_type))) + { + index_sgn = SIGNED; + low_bound + = offset_int::from (wi::to_wide (TYPE_MIN_VALUE (domain_type)), + SIGNED); + } + else + { + index_sgn = TYPE_SIGN (index_type); + low_bound = wi::to_offset (TYPE_MIN_VALUE (domain_type)); + } + } + } + + if (index_type) + access_index = wi::ext (access_index, TYPE_PRECISION (index_type), + index_sgn); + + offset_int index = low_bound; + if (index_type) + index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn); + + offset_int max_index = index; + unsigned cnt; + tree cfield, cval; + bool first_p = true; + + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) + { + /* Array constructor might explicitly set index, or specify a range, + or leave index NULL meaning that it is next index after previous + one. */ + if (cfield) + { + if (TREE_CODE (cfield) == INTEGER_CST) + max_index = index + = offset_int::from (wi::to_wide (cfield), index_sgn); + else + { + gcc_assert (TREE_CODE (cfield) == RANGE_EXPR); + index = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 0)), + index_sgn); + max_index + = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 1)), + index_sgn); + gcc_checking_assert (wi::le_p (index, max_index, index_sgn)); + } + } + else if (!first_p) + { + index = max_index + 1; + if (index_type) + index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn); + gcc_checking_assert (wi::gt_p (index, max_index, index_sgn)); + max_index = index; + } + else + first_p = false; + + /* Do we have match? */ + if (wi::cmp (access_index, index, index_sgn) >= 0) + { + if (wi::cmp (access_index, max_index, index_sgn) <= 0) + { + if (ctor_idx) + *ctor_idx = cnt; + return cval; + } + } + else if (in_gimple_form) + /* We're past the element we search for. Note during parsing + the elements might not be sorted. + ??? We should use a binary search and a flag on the + CONSTRUCTOR as to whether elements are sorted in declaration + order. */ + break; + } + if (ctor_idx) + *ctor_idx = cnt; + return NULL_TREE; +} + +/* Perform constant folding and related simplification of EXPR. + The related simplifications include x*1 => x, x*0 => 0, etc., + and application of the associative law. + NOP_EXPR conversions may be removed freely (as long as we + are careful not to change the type of the overall expression). + We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR, + but we can constant-fold them if they have constant operands. */ + +#ifdef ENABLE_FOLD_CHECKING +# define fold(x) fold_1 (x) +static tree fold_1 (tree); +static +#endif +tree +fold (tree expr) +{ + const tree t = expr; + enum tree_code code = TREE_CODE (t); + enum tree_code_class kind = TREE_CODE_CLASS (code); + tree tem; + location_t loc = EXPR_LOCATION (expr); + + /* Return right away if a constant. */ + if (kind == tcc_constant) + return t; + + /* CALL_EXPR-like objects with variable numbers of operands are + treated specially. */ + if (kind == tcc_vl_exp) + { + if (code == CALL_EXPR) + { + tem = fold_call_expr (loc, expr, false); + return tem ? tem : expr; + } + return expr; + } + + if (IS_EXPR_CODE_CLASS (kind)) + { + tree type = TREE_TYPE (t); + tree op0, op1, op2; + + switch (TREE_CODE_LENGTH (code)) + { + case 1: + op0 = TREE_OPERAND (t, 0); + tem = fold_unary_loc (loc, code, type, op0); + return tem ? tem : expr; + case 2: + op0 = TREE_OPERAND (t, 0); + op1 = TREE_OPERAND (t, 1); + tem = fold_binary_loc (loc, code, type, op0, op1); + return tem ? tem : expr; + case 3: + op0 = TREE_OPERAND (t, 0); + op1 = TREE_OPERAND (t, 1); + op2 = TREE_OPERAND (t, 2); + tem = fold_ternary_loc (loc, code, type, op0, op1, op2); + return tem ? tem : expr; + default: + break; + } + } + + switch (code) + { + case ARRAY_REF: + { + tree op0 = TREE_OPERAND (t, 0); + tree op1 = TREE_OPERAND (t, 1); + + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) == CONSTRUCTOR + && ! type_contains_placeholder_p (TREE_TYPE (op0))) + { + tree val = get_array_ctor_element_at_index (op0, + wi::to_offset (op1)); + if (val) + return val; + } + + return t; + } + + /* Return a VECTOR_CST if possible. */ + case CONSTRUCTOR: + { + tree type = TREE_TYPE (t); + if (TREE_CODE (type) != VECTOR_TYPE) + return t; + + unsigned i; + tree val; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val) + if (! CONSTANT_CLASS_P (val)) + return t; + + return build_vector_from_ctor (type, CONSTRUCTOR_ELTS (t)); + } + + case CONST_DECL: + return fold (DECL_INITIAL (t)); + + default: + return t; + } /* switch (code) */ +} + +#ifdef ENABLE_FOLD_CHECKING +#undef fold + +static void fold_checksum_tree (const_tree, struct md5_ctx *, + hash_table<nofree_ptr_hash<const tree_node> > *); +static void fold_check_failed (const_tree, const_tree); +void print_fold_checksum (const_tree); + +/* When --enable-checking=fold, compute a digest of expr before + and after actual fold call to see if fold did not accidentally + change original expr. */ + +tree +fold (tree expr) +{ + tree ret; + struct md5_ctx ctx; + unsigned char checksum_before[16], checksum_after[16]; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before); + ht.empty (); + + ret = fold_1 (expr); + + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after); + + if (memcmp (checksum_before, checksum_after, 16)) + fold_check_failed (expr, ret); + + return ret; +} + +void +print_fold_checksum (const_tree expr) +{ + struct md5_ctx ctx; + unsigned char checksum[16], cnt; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, &ht); + md5_finish_ctx (&ctx, checksum); + for (cnt = 0; cnt < 16; ++cnt) + fprintf (stderr, "%02x", checksum[cnt]); + putc ('\n', stderr); +} + +static void +fold_check_failed (const_tree expr ATTRIBUTE_UNUSED, const_tree ret ATTRIBUTE_UNUSED) +{ + internal_error ("fold check: original tree changed by fold"); +} + +static void +fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, + hash_table<nofree_ptr_hash <const tree_node> > *ht) +{ + const tree_node **slot; + enum tree_code code; + union tree_node *buf; + int i, len; + + recursive_label: + if (expr == NULL) + return; + slot = ht->find_slot (expr, INSERT); + if (*slot != NULL) + return; + *slot = expr; + code = TREE_CODE (expr); + if (TREE_CODE_CLASS (code) == tcc_declaration + && HAS_DECL_ASSEMBLER_NAME_P (expr)) + { + /* Allow DECL_ASSEMBLER_NAME and symtab_node to be modified. */ + size_t sz = tree_size (expr); + buf = XALLOCAVAR (union tree_node, sz); + memcpy ((char *) buf, expr, sz); + SET_DECL_ASSEMBLER_NAME ((tree) buf, NULL); + buf->decl_with_vis.symtab_node = NULL; + buf->base.nowarning_flag = 0; + expr = (tree) buf; + } + else if (TREE_CODE_CLASS (code) == tcc_type + && (TYPE_POINTER_TO (expr) + || TYPE_REFERENCE_TO (expr) + || TYPE_CACHED_VALUES_P (expr) + || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) + || TYPE_NEXT_VARIANT (expr) + || TYPE_ALIAS_SET_KNOWN_P (expr))) + { + /* Allow these fields to be modified. */ + tree tmp; + size_t sz = tree_size (expr); + buf = XALLOCAVAR (union tree_node, sz); + memcpy ((char *) buf, expr, sz); + expr = tmp = (tree) buf; + TYPE_CONTAINS_PLACEHOLDER_INTERNAL (tmp) = 0; + TYPE_POINTER_TO (tmp) = NULL; + TYPE_REFERENCE_TO (tmp) = NULL; + TYPE_NEXT_VARIANT (tmp) = NULL; + TYPE_ALIAS_SET (tmp) = -1; + if (TYPE_CACHED_VALUES_P (tmp)) + { + TYPE_CACHED_VALUES_P (tmp) = 0; + TYPE_CACHED_VALUES (tmp) = NULL; + } + } + else if (warning_suppressed_p (expr) && (DECL_P (expr) || EXPR_P (expr))) + { + /* Allow the no-warning bit to be set. Perhaps we shouldn't allow + that and change builtins.c etc. instead - see PR89543. */ + size_t sz = tree_size (expr); + buf = XALLOCAVAR (union tree_node, sz); + memcpy ((char *) buf, expr, sz); + buf->base.nowarning_flag = 0; + expr = (tree) buf; + } + md5_process_bytes (expr, tree_size (expr), ctx); + if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) + fold_checksum_tree (TREE_TYPE (expr), ctx, ht); + if (TREE_CODE_CLASS (code) != tcc_type + && TREE_CODE_CLASS (code) != tcc_declaration + && code != TREE_LIST + && code != SSA_NAME + && CODE_CONTAINS_STRUCT (code, TS_COMMON)) + fold_checksum_tree (TREE_CHAIN (expr), ctx, ht); + switch (TREE_CODE_CLASS (code)) + { + case tcc_constant: + switch (code) + { + case STRING_CST: + md5_process_bytes (TREE_STRING_POINTER (expr), + TREE_STRING_LENGTH (expr), ctx); + break; + case COMPLEX_CST: + fold_checksum_tree (TREE_REALPART (expr), ctx, ht); + fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht); + break; + case VECTOR_CST: + len = vector_cst_encoded_nelts (expr); + for (i = 0; i < len; ++i) + fold_checksum_tree (VECTOR_CST_ENCODED_ELT (expr, i), ctx, ht); + break; + default: + break; + } + break; + case tcc_exceptional: + switch (code) + { + case TREE_LIST: + fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht); + fold_checksum_tree (TREE_VALUE (expr), ctx, ht); + expr = TREE_CHAIN (expr); + goto recursive_label; + break; + case TREE_VEC: + for (i = 0; i < TREE_VEC_LENGTH (expr); ++i) + fold_checksum_tree (TREE_VEC_ELT (expr, i), ctx, ht); + break; + default: + break; + } + break; + case tcc_expression: + case tcc_reference: + case tcc_comparison: + case tcc_unary: + case tcc_binary: + case tcc_statement: + case tcc_vl_exp: + len = TREE_OPERAND_LENGTH (expr); + for (i = 0; i < len; ++i) + fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht); + break; + case tcc_declaration: + fold_checksum_tree (DECL_NAME (expr), ctx, ht); + fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht); + if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_COMMON)) + { + fold_checksum_tree (DECL_SIZE (expr), ctx, ht); + fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (DECL_INITIAL (expr), ctx, ht); + fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht); + fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht); + } + + if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_NON_COMMON)) + { + if (TREE_CODE (expr) == FUNCTION_DECL) + { + fold_checksum_tree (DECL_VINDEX (expr), ctx, ht); + fold_checksum_tree (DECL_ARGUMENTS (expr), ctx, ht); + } + fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht); + } + break; + case tcc_type: + if (TREE_CODE (expr) == ENUMERAL_TYPE) + fold_checksum_tree (TYPE_VALUES (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht); + fold_checksum_tree (TYPE_NAME (expr), ctx, ht); + if (INTEGRAL_TYPE_P (expr) + || SCALAR_FLOAT_TYPE_P (expr)) + { + fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht); + fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht); + } + fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht); + if (TREE_CODE (expr) == RECORD_TYPE + || TREE_CODE (expr) == UNION_TYPE + || TREE_CODE (expr) == QUAL_UNION_TYPE) + fold_checksum_tree (TYPE_BINFO (expr), ctx, ht); + fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht); + break; + default: + break; + } +} + +/* Helper function for outputting the checksum of a tree T. When + debugging with gdb, you can "define mynext" to be "next" followed + by "call debug_fold_checksum (op0)", then just trace down till the + outputs differ. */ + +DEBUG_FUNCTION void +debug_fold_checksum (const_tree t) +{ + int i; + unsigned char checksum[16]; + struct md5_ctx ctx; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (t, &ctx, &ht); + md5_finish_ctx (&ctx, checksum); + ht.empty (); + + for (i = 0; i < 16; i++) + fprintf (stderr, "%d ", checksum[i]); + + fprintf (stderr, "\n"); +} + +#endif + +/* Fold a unary tree expression with code CODE of type TYPE with an + operand OP0. LOC is the location of the resulting expression. + Return a folded expression if successful. Otherwise, return a tree + expression with code CODE of type TYPE with an operand OP0. */ + +tree +fold_build1_loc (location_t loc, + enum tree_code code, tree type, tree op0 MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before[16], checksum_after[16]; + struct md5_ctx ctx; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before); + ht.empty (); +#endif + + tem = fold_unary_loc (loc, code, type, op0); + if (!tem) + tem = build1_loc (loc, code, type, op0 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after); + + if (memcmp (checksum_before, checksum_after, 16)) + fold_check_failed (op0, tem); +#endif + return tem; +} + +/* Fold a binary tree expression with code CODE of type TYPE with + operands OP0 and OP1. LOC is the location of the resulting + expression. Return a folded expression if successful. Otherwise, + return a tree expression with code CODE of type TYPE with operands + OP0 and OP1. */ + +tree +fold_build2_loc (location_t loc, + enum tree_code code, tree type, tree op0, tree op1 + MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before_op0[16], + checksum_before_op1[16], + checksum_after_op0[16], + checksum_after_op1[16]; + struct md5_ctx ctx; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_op0); + ht.empty (); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_op1); + ht.empty (); +#endif + + tem = fold_binary_loc (loc, code, type, op0, op1); + if (!tem) + tem = build2_loc (loc, code, type, op0, op1 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_op0); + ht.empty (); + + if (memcmp (checksum_before_op0, checksum_after_op0, 16)) + fold_check_failed (op0, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_op1); + + if (memcmp (checksum_before_op1, checksum_after_op1, 16)) + fold_check_failed (op1, tem); +#endif + return tem; +} + +/* Fold a ternary tree expression with code CODE of type TYPE with + operands OP0, OP1, and OP2. Return a folded expression if + successful. Otherwise, return a tree expression with code CODE of + type TYPE with operands OP0, OP1, and OP2. */ + +tree +fold_build3_loc (location_t loc, enum tree_code code, tree type, + tree op0, tree op1, tree op2 MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before_op0[16], + checksum_before_op1[16], + checksum_before_op2[16], + checksum_after_op0[16], + checksum_after_op1[16], + checksum_after_op2[16]; + struct md5_ctx ctx; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_op0); + ht.empty (); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_op1); + ht.empty (); + + md5_init_ctx (&ctx); + fold_checksum_tree (op2, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_op2); + ht.empty (); +#endif + + gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); + tem = fold_ternary_loc (loc, code, type, op0, op1, op2); + if (!tem) + tem = build3_loc (loc, code, type, op0, op1, op2 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_op0); + ht.empty (); + + if (memcmp (checksum_before_op0, checksum_after_op0, 16)) + fold_check_failed (op0, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_op1); + ht.empty (); + + if (memcmp (checksum_before_op1, checksum_after_op1, 16)) + fold_check_failed (op1, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op2, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_op2); + + if (memcmp (checksum_before_op2, checksum_after_op2, 16)) + fold_check_failed (op2, tem); +#endif + return tem; +} + +/* Fold a CALL_EXPR expression of type TYPE with operands FN and NARGS + arguments in ARGARRAY, and a null static chain. + Return a folded expression if successful. Otherwise, return a CALL_EXPR + of type TYPE from the given operands as constructed by build_call_array. */ + +tree +fold_build_call_array_loc (location_t loc, tree type, tree fn, + int nargs, tree *argarray) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before_fn[16], + checksum_before_arglist[16], + checksum_after_fn[16], + checksum_after_arglist[16]; + struct md5_ctx ctx; + hash_table<nofree_ptr_hash<const tree_node> > ht (32); + int i; + + md5_init_ctx (&ctx); + fold_checksum_tree (fn, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_fn); + ht.empty (); + + md5_init_ctx (&ctx); + for (i = 0; i < nargs; i++) + fold_checksum_tree (argarray[i], &ctx, &ht); + md5_finish_ctx (&ctx, checksum_before_arglist); + ht.empty (); +#endif + + tem = fold_builtin_call_array (loc, type, fn, nargs, argarray); + if (!tem) + tem = build_call_array_loc (loc, type, fn, nargs, argarray); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (fn, &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_fn); + ht.empty (); + + if (memcmp (checksum_before_fn, checksum_after_fn, 16)) + fold_check_failed (fn, tem); + + md5_init_ctx (&ctx); + for (i = 0; i < nargs; i++) + fold_checksum_tree (argarray[i], &ctx, &ht); + md5_finish_ctx (&ctx, checksum_after_arglist); + + if (memcmp (checksum_before_arglist, checksum_after_arglist, 16)) + fold_check_failed (NULL_TREE, tem); +#endif + return tem; +} + +/* Perform constant folding and related simplification of initializer + expression EXPR. These behave identically to "fold_buildN" but ignore + potential run-time traps and exceptions that fold must preserve. */ + +#define START_FOLD_INIT \ + int saved_signaling_nans = flag_signaling_nans;\ + int saved_trapping_math = flag_trapping_math;\ + int saved_rounding_math = flag_rounding_math;\ + int saved_trapv = flag_trapv;\ + int saved_folding_initializer = folding_initializer;\ + flag_signaling_nans = 0;\ + flag_trapping_math = 0;\ + flag_rounding_math = 0;\ + flag_trapv = 0;\ + folding_initializer = 1; + +#define END_FOLD_INIT \ + flag_signaling_nans = saved_signaling_nans;\ + flag_trapping_math = saved_trapping_math;\ + flag_rounding_math = saved_rounding_math;\ + flag_trapv = saved_trapv;\ + folding_initializer = saved_folding_initializer; + +tree +fold_init (tree expr) +{ + tree result; + START_FOLD_INIT; + + result = fold (expr); + + END_FOLD_INIT; + return result; +} + +tree +fold_build1_initializer_loc (location_t loc, enum tree_code code, + tree type, tree op) +{ + tree result; + START_FOLD_INIT; + + result = fold_build1_loc (loc, code, type, op); + + END_FOLD_INIT; + return result; +} + +tree +fold_build2_initializer_loc (location_t loc, enum tree_code code, + tree type, tree op0, tree op1) +{ + tree result; + START_FOLD_INIT; + + result = fold_build2_loc (loc, code, type, op0, op1); + + END_FOLD_INIT; + return result; +} + +tree +fold_build_call_array_initializer_loc (location_t loc, tree type, tree fn, + int nargs, tree *argarray) +{ + tree result; + START_FOLD_INIT; + + result = fold_build_call_array_loc (loc, type, fn, nargs, argarray); + + END_FOLD_INIT; + return result; +} + +tree +fold_binary_initializer_loc (location_t loc, tree_code code, tree type, + tree lhs, tree rhs) +{ + tree result; + START_FOLD_INIT; + + result = fold_binary_loc (loc, code, type, lhs, rhs); + + END_FOLD_INIT; + return result; +} + +#undef START_FOLD_INIT +#undef END_FOLD_INIT + +/* Determine if first argument is a multiple of second argument. Return 0 if + it is not, or we cannot easily determined it to be. + + An example of the sort of thing we care about (at this point; this routine + could surely be made more general, and expanded to do what the *_DIV_EXPR's + fold cases do now) is discovering that + + SAVE_EXPR (I) * SAVE_EXPR (J * 8) + + is a multiple of + + SAVE_EXPR (J * 8) + + when we know that the two SAVE_EXPR (J * 8) nodes are the same node. + + This code also handles discovering that + + SAVE_EXPR (I) * SAVE_EXPR (J * 8) + + is a multiple of 8 so we don't have to worry about dealing with a + possible remainder. + + Note that we *look* inside a SAVE_EXPR only to determine how it was + calculated; it is not safe for fold to do much of anything else with the + internals of a SAVE_EXPR, since it cannot know when it will be evaluated + at run time. For example, the latter example above *cannot* be implemented + as SAVE_EXPR (I) * J or any variant thereof, since the value of J at + evaluation time of the original SAVE_EXPR is not necessarily the same at + the time the new expression is evaluated. The only optimization of this + sort that would be valid is changing + + SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8) + + divided by 8 to + + SAVE_EXPR (I) * SAVE_EXPR (J) + + (where the same SAVE_EXPR (J) is used in the original and the + transformed version). */ + +int +multiple_of_p (tree type, const_tree top, const_tree bottom) +{ + gimple *stmt; + tree t1, op1, op2; + + if (operand_equal_p (top, bottom, 0)) + return 1; + + if (TREE_CODE (type) != INTEGER_TYPE) + return 0; + + switch (TREE_CODE (top)) + { + case BIT_AND_EXPR: + /* Bitwise and provides a power of two multiple. If the mask is + a multiple of BOTTOM then TOP is a multiple of BOTTOM. */ + if (!integer_pow2p (bottom)) + return 0; + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) + || multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); + + case MULT_EXPR: + if (TREE_CODE (bottom) == INTEGER_CST) + { + op1 = TREE_OPERAND (top, 0); + op2 = TREE_OPERAND (top, 1); + if (TREE_CODE (op1) == INTEGER_CST) + std::swap (op1, op2); + if (TREE_CODE (op2) == INTEGER_CST) + { + if (multiple_of_p (type, op2, bottom)) + return 1; + /* Handle multiple_of_p ((x * 2 + 2) * 4, 8). */ + if (multiple_of_p (type, bottom, op2)) + { + widest_int w = wi::sdiv_trunc (wi::to_widest (bottom), + wi::to_widest (op2)); + if (wi::fits_to_tree_p (w, TREE_TYPE (bottom))) + { + op2 = wide_int_to_tree (TREE_TYPE (bottom), w); + return multiple_of_p (type, op1, op2); + } + } + return multiple_of_p (type, op1, bottom); + } + } + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) + || multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); + + case MINUS_EXPR: + /* It is impossible to prove if op0 - op1 is multiple of bottom + precisely, so be conservative here checking if both op0 and op1 + are multiple of bottom. Note we check the second operand first + since it's usually simpler. */ + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) + && multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); + + case PLUS_EXPR: + /* The same as MINUS_EXPR, but handle cases like op0 + 0xfffffffd + as op0 - 3 if the expression has unsigned type. For example, + (X / 3) + 0xfffffffd is multiple of 3, but 0xfffffffd is not. */ + op1 = TREE_OPERAND (top, 1); + if (TYPE_UNSIGNED (type) + && TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sign_bit (op1)) + op1 = fold_build1 (NEGATE_EXPR, type, op1); + return (multiple_of_p (type, op1, bottom) + && multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); + + case LSHIFT_EXPR: + if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST) + { + op1 = TREE_OPERAND (top, 1); + /* const_binop may not detect overflow correctly, + so check for it explicitly here. */ + if (wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), + wi::to_wide (op1)) + && (t1 = fold_convert (type, + const_binop (LSHIFT_EXPR, size_one_node, + op1))) != 0 + && !TREE_OVERFLOW (t1)) + return multiple_of_p (type, t1, bottom); + } + return 0; + + case NOP_EXPR: + /* Can't handle conversions from non-integral or wider integral type. */ + if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE) + || (TYPE_PRECISION (type) + < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0))))) + return 0; + + /* fall through */ + + case SAVE_EXPR: + return multiple_of_p (type, TREE_OPERAND (top, 0), bottom); + + case COND_EXPR: + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) + && multiple_of_p (type, TREE_OPERAND (top, 2), bottom)); + + case INTEGER_CST: + if (TREE_CODE (bottom) != INTEGER_CST + || integer_zerop (bottom) + || (TYPE_UNSIGNED (type) + && (tree_int_cst_sgn (top) < 0 + || tree_int_cst_sgn (bottom) < 0))) + return 0; + return wi::multiple_of_p (wi::to_widest (top), wi::to_widest (bottom), + SIGNED); + + case SSA_NAME: + if (TREE_CODE (bottom) == INTEGER_CST + && (stmt = SSA_NAME_DEF_STMT (top)) != NULL + && gimple_code (stmt) == GIMPLE_ASSIGN) + { + enum tree_code code = gimple_assign_rhs_code (stmt); + + /* Check for special cases to see if top is defined as multiple + of bottom: + + top = (X & ~(bottom - 1) ; bottom is power of 2 + + or + + Y = X % bottom + top = X - Y. */ + if (code == BIT_AND_EXPR + && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE + && TREE_CODE (op2) == INTEGER_CST + && integer_pow2p (bottom) + && wi::multiple_of_p (wi::to_widest (op2), + wi::to_widest (bottom), UNSIGNED)) + return 1; + + op1 = gimple_assign_rhs1 (stmt); + if (code == MINUS_EXPR + && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE + && TREE_CODE (op2) == SSA_NAME + && (stmt = SSA_NAME_DEF_STMT (op2)) != NULL + && gimple_code (stmt) == GIMPLE_ASSIGN + && (code = gimple_assign_rhs_code (stmt)) == TRUNC_MOD_EXPR + && operand_equal_p (op1, gimple_assign_rhs1 (stmt), 0) + && operand_equal_p (bottom, gimple_assign_rhs2 (stmt), 0)) + return 1; + } + + /* fall through */ + + default: + if (POLY_INT_CST_P (top) && poly_int_tree_p (bottom)) + return multiple_p (wi::to_poly_widest (top), + wi::to_poly_widest (bottom)); + + return 0; + } +} + +/* Return true if expression X cannot be (or contain) a NaN or infinity. + This function returns true for integer expressions, and returns + false if uncertain. */ + +bool +tree_expr_finite_p (const_tree x) +{ + machine_mode mode = element_mode (x); + if (!HONOR_NANS (mode) && !HONOR_INFINITIES (mode)) + return true; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_isfinite (TREE_REAL_CST_PTR (x)); + case COMPLEX_CST: + return tree_expr_finite_p (TREE_REALPART (x)) + && tree_expr_finite_p (TREE_IMAGPART (x)); + case FLOAT_EXPR: + return true; + case ABS_EXPR: + case CONVERT_EXPR: + case NON_LVALUE_EXPR: + case NEGATE_EXPR: + case SAVE_EXPR: + return tree_expr_finite_p (TREE_OPERAND (x, 0)); + case MIN_EXPR: + case MAX_EXPR: + return tree_expr_finite_p (TREE_OPERAND (x, 0)) + && tree_expr_finite_p (TREE_OPERAND (x, 1)); + case COND_EXPR: + return tree_expr_finite_p (TREE_OPERAND (x, 1)) + && tree_expr_finite_p (TREE_OPERAND (x, 2)); + case CALL_EXPR: + switch (get_call_combined_fn (x)) + { + CASE_CFN_FABS: + return tree_expr_finite_p (CALL_EXPR_ARG (x, 0)); + CASE_CFN_FMAX: + CASE_CFN_FMIN: + return tree_expr_finite_p (CALL_EXPR_ARG (x, 0)) + && tree_expr_finite_p (CALL_EXPR_ARG (x, 1)); + default: + return false; + } + + default: + return false; + } +} + +/* Return true if expression X evaluates to an infinity. + This function returns false for integer expressions. */ + +bool +tree_expr_infinite_p (const_tree x) +{ + if (!HONOR_INFINITIES (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_isinf (TREE_REAL_CST_PTR (x)); + case ABS_EXPR: + case NEGATE_EXPR: + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_infinite_p (TREE_OPERAND (x, 0)); + case COND_EXPR: + return tree_expr_infinite_p (TREE_OPERAND (x, 1)) + && tree_expr_infinite_p (TREE_OPERAND (x, 2)); + default: + return false; + } +} + +/* Return true if expression X could evaluate to an infinity. + This function returns false for integer expressions, and returns + true if uncertain. */ + +bool +tree_expr_maybe_infinite_p (const_tree x) +{ + if (!HONOR_INFINITIES (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_isinf (TREE_REAL_CST_PTR (x)); + case FLOAT_EXPR: + return false; + case ABS_EXPR: + case NEGATE_EXPR: + return tree_expr_maybe_infinite_p (TREE_OPERAND (x, 0)); + case COND_EXPR: + return tree_expr_maybe_infinite_p (TREE_OPERAND (x, 1)) + || tree_expr_maybe_infinite_p (TREE_OPERAND (x, 2)); + default: + return true; + } +} + +/* Return true if expression X evaluates to a signaling NaN. + This function returns false for integer expressions. */ + +bool +tree_expr_signaling_nan_p (const_tree x) +{ + if (!HONOR_SNANS (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_issignaling_nan (TREE_REAL_CST_PTR (x)); + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_signaling_nan_p (TREE_OPERAND (x, 0)); + case COND_EXPR: + return tree_expr_signaling_nan_p (TREE_OPERAND (x, 1)) + && tree_expr_signaling_nan_p (TREE_OPERAND (x, 2)); + default: + return false; + } +} + +/* Return true if expression X could evaluate to a signaling NaN. + This function returns false for integer expressions, and returns + true if uncertain. */ + +bool +tree_expr_maybe_signaling_nan_p (const_tree x) +{ + if (!HONOR_SNANS (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_issignaling_nan (TREE_REAL_CST_PTR (x)); + case FLOAT_EXPR: + return false; + case ABS_EXPR: + case CONVERT_EXPR: + case NEGATE_EXPR: + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 0)); + case MIN_EXPR: + case MAX_EXPR: + return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 0)) + || tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 1)); + case COND_EXPR: + return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 1)) + || tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 2)); + case CALL_EXPR: + switch (get_call_combined_fn (x)) + { + CASE_CFN_FABS: + return tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 0)); + CASE_CFN_FMAX: + CASE_CFN_FMIN: + return tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 0)) + || tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 1)); + default: + return true; + } + default: + return true; + } +} + +/* Return true if expression X evaluates to a NaN. + This function returns false for integer expressions. */ + +bool +tree_expr_nan_p (const_tree x) +{ + if (!HONOR_NANS (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_isnan (TREE_REAL_CST_PTR (x)); + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_nan_p (TREE_OPERAND (x, 0)); + case COND_EXPR: + return tree_expr_nan_p (TREE_OPERAND (x, 1)) + && tree_expr_nan_p (TREE_OPERAND (x, 2)); + default: + return false; + } +} + +/* Return true if expression X could evaluate to a NaN. + This function returns false for integer expressions, and returns + true if uncertain. */ + +bool +tree_expr_maybe_nan_p (const_tree x) +{ + if (!HONOR_NANS (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return real_isnan (TREE_REAL_CST_PTR (x)); + case FLOAT_EXPR: + return false; + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + return !tree_expr_finite_p (TREE_OPERAND (x, 0)) + || !tree_expr_finite_p (TREE_OPERAND (x, 1)); + case ABS_EXPR: + case CONVERT_EXPR: + case NEGATE_EXPR: + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_maybe_nan_p (TREE_OPERAND (x, 0)); + case MIN_EXPR: + case MAX_EXPR: + return tree_expr_maybe_nan_p (TREE_OPERAND (x, 0)) + || tree_expr_maybe_nan_p (TREE_OPERAND (x, 1)); + case COND_EXPR: + return tree_expr_maybe_nan_p (TREE_OPERAND (x, 1)) + || tree_expr_maybe_nan_p (TREE_OPERAND (x, 2)); + case CALL_EXPR: + switch (get_call_combined_fn (x)) + { + CASE_CFN_FABS: + return tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 0)); + CASE_CFN_FMAX: + CASE_CFN_FMIN: + return tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 0)) + || tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 1)); + default: + return true; + } + default: + return true; + } +} + +/* Return true if expression X could evaluate to -0.0. + This function returns true if uncertain. */ + +bool +tree_expr_maybe_real_minus_zero_p (const_tree x) +{ + if (!HONOR_SIGNED_ZEROS (x)) + return false; + switch (TREE_CODE (x)) + { + case REAL_CST: + return REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (x)); + case INTEGER_CST: + case FLOAT_EXPR: + case ABS_EXPR: + return false; + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 0)); + case COND_EXPR: + return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 1)) + || tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 2)); + case CALL_EXPR: + switch (get_call_combined_fn (x)) + { + CASE_CFN_FABS: + return false; + default: + break; + } + default: + break; + } + /* Ideally !(tree_expr_nonzero_p (X) || tree_expr_nonnegative_p (X)) + * but currently those predicates require tree and not const_tree. */ + return true; +} + +#define tree_expr_nonnegative_warnv_p(X, Y) \ + _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0 + +#define RECURSE(X) \ + ((tree_expr_nonnegative_warnv_p) (X, strict_overflow_p, depth + 1)) + +/* Return true if CODE or TYPE is known to be non-negative. */ + +static bool +tree_simple_nonnegative_warnv_p (enum tree_code code, tree type) +{ + if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type)) + && truth_value_p (code)) + /* Truth values evaluate to 0 or 1, which is nonnegative unless we + have a signed:1 type (where the value is -1 and 0). */ + return true; + return false; +} + +/* Return true if (CODE OP0) is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +bool +tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0, + bool *strict_overflow_p, int depth) +{ + if (TYPE_UNSIGNED (type)) + return true; + + switch (code) + { + case ABS_EXPR: + /* We can't return 1 if flag_wrapv is set because + ABS_EXPR<INT_MIN> = INT_MIN. */ + if (!ANY_INTEGRAL_TYPE_P (type)) + return true; + if (TYPE_OVERFLOW_UNDEFINED (type)) + { + *strict_overflow_p = true; + return true; + } + break; + + case NON_LVALUE_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + return RECURSE (op0); + + CASE_CONVERT: + { + tree inner_type = TREE_TYPE (op0); + tree outer_type = type; + + if (TREE_CODE (outer_type) == REAL_TYPE) + { + if (TREE_CODE (inner_type) == REAL_TYPE) + return RECURSE (op0); + if (INTEGRAL_TYPE_P (inner_type)) + { + if (TYPE_UNSIGNED (inner_type)) + return true; + return RECURSE (op0); + } + } + else if (INTEGRAL_TYPE_P (outer_type)) + { + if (TREE_CODE (inner_type) == REAL_TYPE) + return RECURSE (op0); + if (INTEGRAL_TYPE_P (inner_type)) + return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type) + && TYPE_UNSIGNED (inner_type); + } + } + break; + + default: + return tree_simple_nonnegative_warnv_p (code, type); + } + + /* We don't know sign of `t', so be conservative and return false. */ + return false; +} + +/* Return true if (CODE OP0 OP1) is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +bool +tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0, + tree op1, bool *strict_overflow_p, + int depth) +{ + if (TYPE_UNSIGNED (type)) + return true; + + switch (code) + { + case POINTER_PLUS_EXPR: + case PLUS_EXPR: + if (FLOAT_TYPE_P (type)) + return RECURSE (op0) && RECURSE (op1); + + /* zero_extend(x) + zero_extend(y) is non-negative if x and y are + both unsigned and at least 2 bits shorter than the result. */ + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (op0) == NOP_EXPR + && TREE_CODE (op1) == NOP_EXPR) + { + tree inner1 = TREE_TYPE (TREE_OPERAND (op0, 0)); + tree inner2 = TREE_TYPE (TREE_OPERAND (op1, 0)); + if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1) + && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2)) + { + unsigned int prec = MAX (TYPE_PRECISION (inner1), + TYPE_PRECISION (inner2)) + 1; + return prec < TYPE_PRECISION (type); + } + } + break; + + case MULT_EXPR: + if (FLOAT_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + { + /* x * x is always non-negative for floating point x + or without overflow. */ + if (operand_equal_p (op0, op1, 0) + || (RECURSE (op0) && RECURSE (op1))) + { + if (ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_UNDEFINED (type)) + *strict_overflow_p = true; + return true; + } + } + + /* zero_extend(x) * zero_extend(y) is non-negative if x and y are + both unsigned and their total bits is shorter than the result. */ + if (TREE_CODE (type) == INTEGER_TYPE + && (TREE_CODE (op0) == NOP_EXPR || TREE_CODE (op0) == INTEGER_CST) + && (TREE_CODE (op1) == NOP_EXPR || TREE_CODE (op1) == INTEGER_CST)) + { + tree inner0 = (TREE_CODE (op0) == NOP_EXPR) + ? TREE_TYPE (TREE_OPERAND (op0, 0)) + : TREE_TYPE (op0); + tree inner1 = (TREE_CODE (op1) == NOP_EXPR) + ? TREE_TYPE (TREE_OPERAND (op1, 0)) + : TREE_TYPE (op1); + + bool unsigned0 = TYPE_UNSIGNED (inner0); + bool unsigned1 = TYPE_UNSIGNED (inner1); + + if (TREE_CODE (op0) == INTEGER_CST) + unsigned0 = unsigned0 || tree_int_cst_sgn (op0) >= 0; + + if (TREE_CODE (op1) == INTEGER_CST) + unsigned1 = unsigned1 || tree_int_cst_sgn (op1) >= 0; + + if (TREE_CODE (inner0) == INTEGER_TYPE && unsigned0 + && TREE_CODE (inner1) == INTEGER_TYPE && unsigned1) + { + unsigned int precision0 = (TREE_CODE (op0) == INTEGER_CST) + ? tree_int_cst_min_precision (op0, UNSIGNED) + : TYPE_PRECISION (inner0); + + unsigned int precision1 = (TREE_CODE (op1) == INTEGER_CST) + ? tree_int_cst_min_precision (op1, UNSIGNED) + : TYPE_PRECISION (inner1); + + return precision0 + precision1 < TYPE_PRECISION (type); + } + } + return false; + + case BIT_AND_EXPR: + return RECURSE (op0) || RECURSE (op1); + + case MAX_EXPR: + /* Usually RECURSE (op0) || RECURSE (op1) but NaNs complicate + things. */ + if (tree_expr_maybe_nan_p (op0) || tree_expr_maybe_nan_p (op1)) + return RECURSE (op0) && RECURSE (op1); + return RECURSE (op0) || RECURSE (op1); + + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case MIN_EXPR: + case RDIV_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + return RECURSE (op0) && RECURSE (op1); + + case TRUNC_MOD_EXPR: + return RECURSE (op0); + + case FLOOR_MOD_EXPR: + return RECURSE (op1); + + case CEIL_MOD_EXPR: + case ROUND_MOD_EXPR: + default: + return tree_simple_nonnegative_warnv_p (code, type); + } + + /* We don't know sign of `t', so be conservative and return false. */ + return false; +} + +/* Return true if T is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +bool +tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) +{ + if (TYPE_UNSIGNED (TREE_TYPE (t))) + return true; + + switch (TREE_CODE (t)) + { + case INTEGER_CST: + return tree_int_cst_sgn (t) >= 0; + + case REAL_CST: + return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); + + case FIXED_CST: + return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t)); + + case COND_EXPR: + return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2)); + + case SSA_NAME: + /* Limit the depth of recursion to avoid quadratic behavior. + This is expected to catch almost all occurrences in practice. + If this code misses important cases that unbounded recursion + would not, passes that need this information could be revised + to provide it through dataflow propagation. */ + return (!name_registered_for_update_p (t) + && depth < param_max_ssa_name_query_depth + && gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t), + strict_overflow_p, depth)); + + default: + return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t)); + } +} + +/* Return true if T is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +bool +tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1, + bool *strict_overflow_p, int depth) +{ + switch (fn) + { + CASE_CFN_ACOS: + CASE_CFN_ACOSH: + CASE_CFN_CABS: + CASE_CFN_COSH: + CASE_CFN_ERFC: + CASE_CFN_EXP: + CASE_CFN_EXP10: + CASE_CFN_EXP2: + CASE_CFN_FABS: + CASE_CFN_FDIM: + CASE_CFN_HYPOT: + CASE_CFN_POW10: + CASE_CFN_FFS: + CASE_CFN_PARITY: + CASE_CFN_POPCOUNT: + CASE_CFN_CLZ: + CASE_CFN_CLRSB: + case CFN_BUILT_IN_BSWAP16: + case CFN_BUILT_IN_BSWAP32: + case CFN_BUILT_IN_BSWAP64: + case CFN_BUILT_IN_BSWAP128: + /* Always true. */ + return true; + + CASE_CFN_SQRT: + CASE_CFN_SQRT_FN: + /* sqrt(-0.0) is -0.0. */ + if (!HONOR_SIGNED_ZEROS (type)) + return true; + return RECURSE (arg0); + + CASE_CFN_ASINH: + CASE_CFN_ATAN: + CASE_CFN_ATANH: + CASE_CFN_CBRT: + CASE_CFN_CEIL: + CASE_CFN_CEIL_FN: + CASE_CFN_ERF: + CASE_CFN_EXPM1: + CASE_CFN_FLOOR: + CASE_CFN_FLOOR_FN: + CASE_CFN_FMOD: + CASE_CFN_FREXP: + CASE_CFN_ICEIL: + CASE_CFN_IFLOOR: + CASE_CFN_IRINT: + CASE_CFN_IROUND: + CASE_CFN_LCEIL: + CASE_CFN_LDEXP: + CASE_CFN_LFLOOR: + CASE_CFN_LLCEIL: + CASE_CFN_LLFLOOR: + CASE_CFN_LLRINT: + CASE_CFN_LLROUND: + CASE_CFN_LRINT: + CASE_CFN_LROUND: + CASE_CFN_MODF: + CASE_CFN_NEARBYINT: + CASE_CFN_NEARBYINT_FN: + CASE_CFN_RINT: + CASE_CFN_RINT_FN: + CASE_CFN_ROUND: + CASE_CFN_ROUND_FN: + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: + CASE_CFN_SCALB: + CASE_CFN_SCALBLN: + CASE_CFN_SCALBN: + CASE_CFN_SIGNBIT: + CASE_CFN_SIGNIFICAND: + CASE_CFN_SINH: + CASE_CFN_TANH: + CASE_CFN_TRUNC: + CASE_CFN_TRUNC_FN: + /* True if the 1st argument is nonnegative. */ + return RECURSE (arg0); + + CASE_CFN_FMAX: + CASE_CFN_FMAX_FN: + /* Usually RECURSE (arg0) || RECURSE (arg1) but NaNs complicate + things. In the presence of sNaNs, we're only guaranteed to be + non-negative if both operands are non-negative. In the presence + of qNaNs, we're non-negative if either operand is non-negative + and can't be a qNaN, or if both operands are non-negative. */ + if (tree_expr_maybe_signaling_nan_p (arg0) || + tree_expr_maybe_signaling_nan_p (arg1)) + return RECURSE (arg0) && RECURSE (arg1); + return RECURSE (arg0) ? (!tree_expr_maybe_nan_p (arg0) + || RECURSE (arg1)) + : (RECURSE (arg1) + && !tree_expr_maybe_nan_p (arg1)); + + CASE_CFN_FMIN: + CASE_CFN_FMIN_FN: + /* True if the 1st AND 2nd arguments are nonnegative. */ + return RECURSE (arg0) && RECURSE (arg1); + + CASE_CFN_COPYSIGN: + CASE_CFN_COPYSIGN_FN: + /* True if the 2nd argument is nonnegative. */ + return RECURSE (arg1); + + CASE_CFN_POWI: + /* True if the 1st argument is nonnegative or the second + argument is an even integer. */ + if (TREE_CODE (arg1) == INTEGER_CST + && (TREE_INT_CST_LOW (arg1) & 1) == 0) + return true; + return RECURSE (arg0); + + CASE_CFN_POW: + /* True if the 1st argument is nonnegative or the second + argument is an even integer valued real. */ + if (TREE_CODE (arg1) == REAL_CST) + { + REAL_VALUE_TYPE c; + HOST_WIDE_INT n; + + c = TREE_REAL_CST (arg1); + n = real_to_integer (&c); + if ((n & 1) == 0) + { + REAL_VALUE_TYPE cint; + real_from_integer (&cint, VOIDmode, n, SIGNED); + if (real_identical (&c, &cint)) + return true; + } + } + return RECURSE (arg0); + + default: + break; + } + return tree_simple_nonnegative_warnv_p (CALL_EXPR, type); +} + +/* Return true if T is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +static bool +tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) +{ + enum tree_code code = TREE_CODE (t); + if (TYPE_UNSIGNED (TREE_TYPE (t))) + return true; + + switch (code) + { + case TARGET_EXPR: + { + tree temp = TARGET_EXPR_SLOT (t); + t = TARGET_EXPR_INITIAL (t); + + /* If the initializer is non-void, then it's a normal expression + that will be assigned to the slot. */ + if (!VOID_TYPE_P (t)) + return RECURSE (t); + + /* Otherwise, the initializer sets the slot in some way. One common + way is an assignment statement at the end of the initializer. */ + while (1) + { + if (TREE_CODE (t) == BIND_EXPR) + t = expr_last (BIND_EXPR_BODY (t)); + else if (TREE_CODE (t) == TRY_FINALLY_EXPR + || TREE_CODE (t) == TRY_CATCH_EXPR) + t = expr_last (TREE_OPERAND (t, 0)); + else if (TREE_CODE (t) == STATEMENT_LIST) + t = expr_last (t); + else + break; + } + if (TREE_CODE (t) == MODIFY_EXPR + && TREE_OPERAND (t, 0) == temp) + return RECURSE (TREE_OPERAND (t, 1)); + + return false; + } + + case CALL_EXPR: + { + tree arg0 = call_expr_nargs (t) > 0 ? CALL_EXPR_ARG (t, 0) : NULL_TREE; + tree arg1 = call_expr_nargs (t) > 1 ? CALL_EXPR_ARG (t, 1) : NULL_TREE; + + return tree_call_nonnegative_warnv_p (TREE_TYPE (t), + get_call_combined_fn (t), + arg0, + arg1, + strict_overflow_p, depth); + } + case COMPOUND_EXPR: + case MODIFY_EXPR: + return RECURSE (TREE_OPERAND (t, 1)); + + case BIND_EXPR: + return RECURSE (expr_last (TREE_OPERAND (t, 1))); + + case SAVE_EXPR: + return RECURSE (TREE_OPERAND (t, 0)); + + default: + return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t)); + } +} + +#undef RECURSE +#undef tree_expr_nonnegative_warnv_p + +/* Return true if T is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */ + +bool +tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) +{ + enum tree_code code; + if (t == error_mark_node) + return false; + + code = TREE_CODE (t); + switch (TREE_CODE_CLASS (code)) + { + case tcc_binary: + case tcc_comparison: + return tree_binary_nonnegative_warnv_p (TREE_CODE (t), + TREE_TYPE (t), + TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), + strict_overflow_p, depth); + + case tcc_unary: + return tree_unary_nonnegative_warnv_p (TREE_CODE (t), + TREE_TYPE (t), + TREE_OPERAND (t, 0), + strict_overflow_p, depth); + + case tcc_constant: + case tcc_declaration: + case tcc_reference: + return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth); + + default: + break; + } + + switch (code) + { + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + return tree_binary_nonnegative_warnv_p (TREE_CODE (t), + TREE_TYPE (t), + TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), + strict_overflow_p, depth); + case TRUTH_NOT_EXPR: + return tree_unary_nonnegative_warnv_p (TREE_CODE (t), + TREE_TYPE (t), + TREE_OPERAND (t, 0), + strict_overflow_p, depth); + + case COND_EXPR: + case CONSTRUCTOR: + case OBJ_TYPE_REF: + case ASSERT_EXPR: + case ADDR_EXPR: + case WITH_SIZE_EXPR: + case SSA_NAME: + return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth); + + default: + return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p, depth); + } +} + +/* Return true if `t' is known to be non-negative. Handle warnings + about undefined signed overflow. */ + +bool +tree_expr_nonnegative_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonnegative_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-negative"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + + +/* Return true when (CODE OP0) is an address and is known to be nonzero. + For floating point we further ensure that T is not denormal. + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ + +bool +tree_unary_nonzero_warnv_p (enum tree_code code, tree type, tree op0, + bool *strict_overflow_p) +{ + switch (code) + { + case ABS_EXPR: + return tree_expr_nonzero_warnv_p (op0, + strict_overflow_p); + + case NOP_EXPR: + { + tree inner_type = TREE_TYPE (op0); + tree outer_type = type; + + return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) + && tree_expr_nonzero_warnv_p (op0, + strict_overflow_p)); + } + break; + + case NON_LVALUE_EXPR: + return tree_expr_nonzero_warnv_p (op0, + strict_overflow_p); + + default: + break; + } + + return false; +} + +/* Return true when (CODE OP0 OP1) is an address and is known to be nonzero. + For floating point we further ensure that T is not denormal. + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ + +bool +tree_binary_nonzero_warnv_p (enum tree_code code, + tree type, + tree op0, + tree op1, bool *strict_overflow_p) +{ + bool sub_strict_overflow_p; + switch (code) + { + case POINTER_PLUS_EXPR: + case PLUS_EXPR: + if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type)) + { + /* With the presence of negative values it is hard + to say something. */ + sub_strict_overflow_p = false; + if (!tree_expr_nonnegative_warnv_p (op0, + &sub_strict_overflow_p) + || !tree_expr_nonnegative_warnv_p (op1, + &sub_strict_overflow_p)) + return false; + /* One of operands must be positive and the other non-negative. */ + /* We don't set *STRICT_OVERFLOW_P here: even if this value + overflows, on a twos-complement machine the sum of two + nonnegative numbers can never be zero. */ + return (tree_expr_nonzero_warnv_p (op0, + strict_overflow_p) + || tree_expr_nonzero_warnv_p (op1, + strict_overflow_p)); + } + break; + + case MULT_EXPR: + if (TYPE_OVERFLOW_UNDEFINED (type)) + { + if (tree_expr_nonzero_warnv_p (op0, + strict_overflow_p) + && tree_expr_nonzero_warnv_p (op1, + strict_overflow_p)) + { + *strict_overflow_p = true; + return true; + } + } + break; + + case MIN_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (op0, + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (op1, + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + } + break; + + case MAX_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (op0, + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + + /* When both operands are nonzero, then MAX must be too. */ + if (tree_expr_nonzero_warnv_p (op1, + strict_overflow_p)) + return true; + + /* MAX where operand 0 is positive is positive. */ + return tree_expr_nonnegative_warnv_p (op0, + strict_overflow_p); + } + /* MAX where operand 1 is positive is positive. */ + else if (tree_expr_nonzero_warnv_p (op1, + &sub_strict_overflow_p) + && tree_expr_nonnegative_warnv_p (op1, + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; + + case BIT_IOR_EXPR: + return (tree_expr_nonzero_warnv_p (op1, + strict_overflow_p) + || tree_expr_nonzero_warnv_p (op0, + strict_overflow_p)); + + default: + break; + } + + return false; +} + +/* Return true when T is an address and is known to be nonzero. + For floating point we further ensure that T is not denormal. + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ + +bool +tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p) +{ + bool sub_strict_overflow_p; + switch (TREE_CODE (t)) + { + case INTEGER_CST: + return !integer_zerop (t); + + case ADDR_EXPR: + { + tree base = TREE_OPERAND (t, 0); + + if (!DECL_P (base)) + base = get_base_address (base); + + if (base && TREE_CODE (base) == TARGET_EXPR) + base = TARGET_EXPR_SLOT (base); + + if (!base) + return false; + + /* For objects in symbol table check if we know they are non-zero. + Don't do anything for variables and functions before symtab is built; + it is quite possible that they will be declared weak later. */ + int nonzero_addr = maybe_nonzero_address (base); + if (nonzero_addr >= 0) + return nonzero_addr; + + /* Constants are never weak. */ + if (CONSTANT_CLASS_P (base)) + return true; + + return false; + } + + case COND_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 2), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; + + case SSA_NAME: + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + break; + return expr_not_equal_to (t, wi::zero (TYPE_PRECISION (TREE_TYPE (t)))); + + default: + break; + } + return false; +} + +#define integer_valued_real_p(X) \ + _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0 + +#define RECURSE(X) \ + ((integer_valued_real_p) (X, depth + 1)) + +/* Return true if the floating point result of (CODE OP0) has an + integer value. We also allow +Inf, -Inf and NaN to be considered + integer values. Return false for signaling NaN. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_unary_p (tree_code code, tree op0, int depth) +{ + switch (code) + { + case FLOAT_EXPR: + return true; + + case ABS_EXPR: + return RECURSE (op0); + + CASE_CONVERT: + { + tree type = TREE_TYPE (op0); + if (TREE_CODE (type) == INTEGER_TYPE) + return true; + if (TREE_CODE (type) == REAL_TYPE) + return RECURSE (op0); + break; + } + + default: + break; + } + return false; +} + +/* Return true if the floating point result of (CODE OP0 OP1) has an + integer value. We also allow +Inf, -Inf and NaN to be considered + integer values. Return false for signaling NaN. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_binary_p (tree_code code, tree op0, tree op1, int depth) +{ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case MIN_EXPR: + case MAX_EXPR: + return RECURSE (op0) && RECURSE (op1); + + default: + break; + } + return false; +} + +/* Return true if the floating point result of calling FNDECL with arguments + ARG0 and ARG1 has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. Return false for signaling NaN. If FNDECL + takes fewer than 2 arguments, the remaining ARGn are null. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_call_p (combined_fn fn, tree arg0, tree arg1, int depth) +{ + switch (fn) + { + CASE_CFN_CEIL: + CASE_CFN_CEIL_FN: + CASE_CFN_FLOOR: + CASE_CFN_FLOOR_FN: + CASE_CFN_NEARBYINT: + CASE_CFN_NEARBYINT_FN: + CASE_CFN_RINT: + CASE_CFN_RINT_FN: + CASE_CFN_ROUND: + CASE_CFN_ROUND_FN: + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: + CASE_CFN_TRUNC: + CASE_CFN_TRUNC_FN: + return true; + + CASE_CFN_FMIN: + CASE_CFN_FMIN_FN: + CASE_CFN_FMAX: + CASE_CFN_FMAX_FN: + return RECURSE (arg0) && RECURSE (arg1); + + default: + break; + } + return false; +} + +/* Return true if the floating point expression T (a GIMPLE_SINGLE_RHS) + has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. Return false for signaling NaN. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_single_p (tree t, int depth) +{ + switch (TREE_CODE (t)) + { + case REAL_CST: + return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t))); + + case COND_EXPR: + return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2)); + + case SSA_NAME: + /* Limit the depth of recursion to avoid quadratic behavior. + This is expected to catch almost all occurrences in practice. + If this code misses important cases that unbounded recursion + would not, passes that need this information could be revised + to provide it through dataflow propagation. */ + return (!name_registered_for_update_p (t) + && depth < param_max_ssa_name_query_depth + && gimple_stmt_integer_valued_real_p (SSA_NAME_DEF_STMT (t), + depth)); + + default: + break; + } + return false; +} + +/* Return true if the floating point expression T (a GIMPLE_INVALID_RHS) + has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. Return false for signaling NaN. + + DEPTH is the current nesting depth of the query. */ + +static bool +integer_valued_real_invalid_p (tree t, int depth) +{ + switch (TREE_CODE (t)) + { + case COMPOUND_EXPR: + case MODIFY_EXPR: + case BIND_EXPR: + return RECURSE (TREE_OPERAND (t, 1)); + + case SAVE_EXPR: + return RECURSE (TREE_OPERAND (t, 0)); + + default: + break; + } + return false; +} + +#undef RECURSE +#undef integer_valued_real_p + +/* Return true if the floating point expression T has an integer value. + We also allow +Inf, -Inf and NaN to be considered integer values. + Return false for signaling NaN. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_p (tree t, int depth) +{ + if (t == error_mark_node) + return false; + + STRIP_ANY_LOCATION_WRAPPER (t); + + tree_code code = TREE_CODE (t); + switch (TREE_CODE_CLASS (code)) + { + case tcc_binary: + case tcc_comparison: + return integer_valued_real_binary_p (code, TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), depth); + + case tcc_unary: + return integer_valued_real_unary_p (code, TREE_OPERAND (t, 0), depth); + + case tcc_constant: + case tcc_declaration: + case tcc_reference: + return integer_valued_real_single_p (t, depth); + + default: + break; + } + + switch (code) + { + case COND_EXPR: + case SSA_NAME: + return integer_valued_real_single_p (t, depth); + + case CALL_EXPR: + { + tree arg0 = (call_expr_nargs (t) > 0 + ? CALL_EXPR_ARG (t, 0) + : NULL_TREE); + tree arg1 = (call_expr_nargs (t) > 1 + ? CALL_EXPR_ARG (t, 1) + : NULL_TREE); + return integer_valued_real_call_p (get_call_combined_fn (t), + arg0, arg1, depth); + } + + default: + return integer_valued_real_invalid_p (t, depth); + } +} + +/* Given the components of a binary expression CODE, TYPE, OP0 and OP1, + attempt to fold the expression to a constant without modifying TYPE, + OP0 or OP1. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. */ + +tree +fold_binary_to_constant (enum tree_code code, tree type, tree op0, tree op1) +{ + tree tem = fold_binary (code, type, op0, op1); + return (tem && TREE_CONSTANT (tem)) ? tem : NULL_TREE; +} + +/* Given the components of a unary expression CODE, TYPE and OP0, + attempt to fold the expression to a constant without modifying + TYPE or OP0. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. */ + +tree +fold_unary_to_constant (enum tree_code code, tree type, tree op0) +{ + tree tem = fold_unary (code, type, op0); + return (tem && TREE_CONSTANT (tem)) ? tem : NULL_TREE; +} + +/* If EXP represents referencing an element in a constant string + (either via pointer arithmetic or array indexing), return the + tree representing the value accessed, otherwise return NULL. */ + +tree +fold_read_from_constant_string (tree exp) +{ + if ((TREE_CODE (exp) == INDIRECT_REF + || TREE_CODE (exp) == ARRAY_REF) + && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE) + { + tree exp1 = TREE_OPERAND (exp, 0); + tree index; + tree string; + location_t loc = EXPR_LOCATION (exp); + + if (TREE_CODE (exp) == INDIRECT_REF) + string = string_constant (exp1, &index, NULL, NULL); + else + { + tree low_bound = array_ref_low_bound (exp); + index = fold_convert_loc (loc, sizetype, TREE_OPERAND (exp, 1)); + + /* Optimize the special-case of a zero lower bound. + + We convert the low_bound to sizetype to avoid some problems + with constant folding. (E.g. suppose the lower bound is 1, + and its mode is QI. Without the conversion,l (ARRAY + +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1)) + +INDEX), which becomes (ARRAY+255+INDEX). Oops!) */ + if (! integer_zerop (low_bound)) + index = size_diffop_loc (loc, index, + fold_convert_loc (loc, sizetype, low_bound)); + + string = exp1; + } + + scalar_int_mode char_mode; + if (string + && TYPE_MODE (TREE_TYPE (exp)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (string))) + && TREE_CODE (string) == STRING_CST + && tree_fits_uhwi_p (index) + && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0 + && is_int_mode (TYPE_MODE (TREE_TYPE (TREE_TYPE (string))), + &char_mode) + && GET_MODE_SIZE (char_mode) == 1) + return build_int_cst_type (TREE_TYPE (exp), + (TREE_STRING_POINTER (string) + [TREE_INT_CST_LOW (index)])); + } + return NULL; +} + +/* Folds a read from vector element at IDX of vector ARG. */ + +tree +fold_read_from_vector (tree arg, poly_uint64 idx) +{ + unsigned HOST_WIDE_INT i; + if (known_lt (idx, TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg))) + && known_ge (idx, 0u) + && idx.is_constant (&i)) + { + if (TREE_CODE (arg) == VECTOR_CST) + return VECTOR_CST_ELT (arg, i); + else if (TREE_CODE (arg) == CONSTRUCTOR) + { + if (CONSTRUCTOR_NELTS (arg) + && VECTOR_TYPE_P (TREE_TYPE (CONSTRUCTOR_ELT (arg, 0)->value))) + return NULL_TREE; + if (i >= CONSTRUCTOR_NELTS (arg)) + return build_zero_cst (TREE_TYPE (TREE_TYPE (arg))); + return CONSTRUCTOR_ELT (arg, i)->value; + } + } + return NULL_TREE; +} + +/* Return the tree for neg (ARG0) when ARG0 is known to be either + an integer constant, real, or fixed-point constant. + + TYPE is the type of the result. */ + +static tree +fold_negate_const (tree arg0, tree type) +{ + tree t = NULL_TREE; + + switch (TREE_CODE (arg0)) + { + case REAL_CST: + t = build_real (type, real_value_negate (&TREE_REAL_CST (arg0))); + break; + + case FIXED_CST: + { + FIXED_VALUE_TYPE f; + bool overflow_p = fixed_arithmetic (&f, NEGATE_EXPR, + &(TREE_FIXED_CST (arg0)), NULL, + TYPE_SATURATING (type)); + t = build_fixed (type, f); + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg0)) + TREE_OVERFLOW (t) = 1; + break; + } + + default: + if (poly_int_tree_p (arg0)) + { + wi::overflow_type overflow; + poly_wide_int res = wi::neg (wi::to_poly_wide (arg0), &overflow); + t = force_fit_type (type, res, 1, + (overflow && ! TYPE_UNSIGNED (type)) + || TREE_OVERFLOW (arg0)); + break; + } + + gcc_unreachable (); + } + + return t; +} + +/* Return the tree for abs (ARG0) when ARG0 is known to be either + an integer constant or real constant. + + TYPE is the type of the result. */ + +tree +fold_abs_const (tree arg0, tree type) +{ + tree t = NULL_TREE; + + switch (TREE_CODE (arg0)) + { + case INTEGER_CST: + { + /* If the value is unsigned or non-negative, then the absolute value + is the same as the ordinary value. */ + wide_int val = wi::to_wide (arg0); + wi::overflow_type overflow = wi::OVF_NONE; + if (!wi::neg_p (val, TYPE_SIGN (TREE_TYPE (arg0)))) + ; + + /* If the value is negative, then the absolute value is + its negation. */ + else + val = wi::neg (val, &overflow); + + /* Force to the destination type, set TREE_OVERFLOW for signed + TYPE only. */ + t = force_fit_type (type, val, 1, overflow | TREE_OVERFLOW (arg0)); + } + break; + + case REAL_CST: + if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0))) + t = build_real (type, real_value_negate (&TREE_REAL_CST (arg0))); + else + t = arg0; + break; + + default: + gcc_unreachable (); + } + + return t; +} + +/* Return the tree for not (ARG0) when ARG0 is known to be an integer + constant. TYPE is the type of the result. */ + +static tree +fold_not_const (const_tree arg0, tree type) +{ + gcc_assert (TREE_CODE (arg0) == INTEGER_CST); + + return force_fit_type (type, ~wi::to_wide (arg0), 0, TREE_OVERFLOW (arg0)); +} + +/* Given CODE, a relational operator, the target type, TYPE and two + constant operands OP0 and OP1, return the result of the + relational operation. If the result is not a compile time + constant, then return NULL_TREE. */ + +static tree +fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) +{ + int result, invert; + + /* From here on, the only cases we handle are when the result is + known to be a constant. */ + + if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST) + { + const REAL_VALUE_TYPE *c0 = TREE_REAL_CST_PTR (op0); + const REAL_VALUE_TYPE *c1 = TREE_REAL_CST_PTR (op1); + + /* Handle the cases where either operand is a NaN. */ + if (real_isnan (c0) || real_isnan (c1)) + { + switch (code) + { + case EQ_EXPR: + case ORDERED_EXPR: + result = 0; + break; + + case NE_EXPR: + case UNORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + result = 1; + break; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LTGT_EXPR: + if (flag_trapping_math) + return NULL_TREE; + result = 0; + break; + + default: + gcc_unreachable (); + } + + return constant_boolean_node (result, type); + } + + return constant_boolean_node (real_compare (code, c0, c1), type); + } + + if (TREE_CODE (op0) == FIXED_CST && TREE_CODE (op1) == FIXED_CST) + { + const FIXED_VALUE_TYPE *c0 = TREE_FIXED_CST_PTR (op0); + const FIXED_VALUE_TYPE *c1 = TREE_FIXED_CST_PTR (op1); + return constant_boolean_node (fixed_compare (code, c0, c1), type); + } + + /* Handle equality/inequality of complex constants. */ + if (TREE_CODE (op0) == COMPLEX_CST && TREE_CODE (op1) == COMPLEX_CST) + { + tree rcond = fold_relational_const (code, type, + TREE_REALPART (op0), + TREE_REALPART (op1)); + tree icond = fold_relational_const (code, type, + TREE_IMAGPART (op0), + TREE_IMAGPART (op1)); + if (code == EQ_EXPR) + return fold_build2 (TRUTH_ANDIF_EXPR, type, rcond, icond); + else if (code == NE_EXPR) + return fold_build2 (TRUTH_ORIF_EXPR, type, rcond, icond); + else + return NULL_TREE; + } + + if (TREE_CODE (op0) == VECTOR_CST && TREE_CODE (op1) == VECTOR_CST) + { + if (!VECTOR_TYPE_P (type)) + { + /* Have vector comparison with scalar boolean result. */ + gcc_assert ((code == EQ_EXPR || code == NE_EXPR) + && known_eq (VECTOR_CST_NELTS (op0), + VECTOR_CST_NELTS (op1))); + unsigned HOST_WIDE_INT nunits; + if (!VECTOR_CST_NELTS (op0).is_constant (&nunits)) + return NULL_TREE; + for (unsigned i = 0; i < nunits; i++) + { + tree elem0 = VECTOR_CST_ELT (op0, i); + tree elem1 = VECTOR_CST_ELT (op1, i); + tree tmp = fold_relational_const (EQ_EXPR, type, elem0, elem1); + if (tmp == NULL_TREE) + return NULL_TREE; + if (integer_zerop (tmp)) + return constant_boolean_node (code == NE_EXPR, type); + } + return constant_boolean_node (code == EQ_EXPR, type); + } + tree_vector_builder elts; + if (!elts.new_binary_operation (type, op0, op1, false)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned i = 0; i < count; i++) + { + tree elem_type = TREE_TYPE (type); + tree elem0 = VECTOR_CST_ELT (op0, i); + tree elem1 = VECTOR_CST_ELT (op1, i); + + tree tem = fold_relational_const (code, elem_type, + elem0, elem1); + + if (tem == NULL_TREE) + return NULL_TREE; + + elts.quick_push (build_int_cst (elem_type, + integer_zerop (tem) ? 0 : -1)); + } + + return elts.build (); + } + + /* From here on we only handle LT, LE, GT, GE, EQ and NE. + + To compute GT, swap the arguments and do LT. + To compute GE, do LT and invert the result. + To compute LE, swap the arguments, do LT and invert the result. + To compute NE, do EQ and invert the result. + + Therefore, the code below must handle only EQ and LT. */ + + if (code == LE_EXPR || code == GT_EXPR) + { + std::swap (op0, op1); + code = swap_tree_comparison (code); + } + + /* Note that it is safe to invert for real values here because we + have already handled the one case that it matters. */ + + invert = 0; + if (code == NE_EXPR || code == GE_EXPR) + { + invert = 1; + code = invert_tree_comparison (code, false); + } + + /* Compute a result for LT or EQ if args permit; + Otherwise return T. */ + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + if (code == EQ_EXPR) + result = tree_int_cst_equal (op0, op1); + else + result = tree_int_cst_lt (op0, op1); + } + else + return NULL_TREE; + + if (invert) + result ^= 1; + return constant_boolean_node (result, type); +} + +/* If necessary, return a CLEANUP_POINT_EXPR for EXPR with the + indicated TYPE. If no CLEANUP_POINT_EXPR is necessary, return EXPR + itself. */ + +tree +fold_build_cleanup_point_expr (tree type, tree expr) +{ + /* If the expression does not have side effects then we don't have to wrap + it with a cleanup point expression. */ + if (!TREE_SIDE_EFFECTS (expr)) + return expr; + + /* If the expression is a return, check to see if the expression inside the + return has no side effects or the right hand side of the modify expression + inside the return. If either don't have side effects set we don't need to + wrap the expression in a cleanup point expression. Note we don't check the + left hand side of the modify because it should always be a return decl. */ + if (TREE_CODE (expr) == RETURN_EXPR) + { + tree op = TREE_OPERAND (expr, 0); + if (!op || !TREE_SIDE_EFFECTS (op)) + return expr; + op = TREE_OPERAND (op, 1); + if (!TREE_SIDE_EFFECTS (op)) + return expr; + } + + return build1_loc (EXPR_LOCATION (expr), CLEANUP_POINT_EXPR, type, expr); +} + +/* Given a pointer value OP0 and a type TYPE, return a simplified version + of an indirection through OP0, or NULL_TREE if no simplification is + possible. */ + +tree +fold_indirect_ref_1 (location_t loc, tree type, tree op0) +{ + tree sub = op0; + tree subtype; + poly_uint64 const_op01; + + STRIP_NOPS (sub); + subtype = TREE_TYPE (sub); + if (!POINTER_TYPE_P (subtype) + || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (op0))) + return NULL_TREE; + + if (TREE_CODE (sub) == ADDR_EXPR) + { + tree op = TREE_OPERAND (sub, 0); + tree optype = TREE_TYPE (op); + + /* *&CONST_DECL -> to the value of the const decl. */ + if (TREE_CODE (op) == CONST_DECL) + return DECL_INITIAL (op); + /* *&p => p; make sure to handle *&"str"[cst] here. */ + if (type == optype) + { + tree fop = fold_read_from_constant_string (op); + if (fop) + return fop; + else + return op; + } + /* *(foo *)&fooarray => fooarray[0] */ + else if (TREE_CODE (optype) == ARRAY_TYPE + && type == TREE_TYPE (optype) + && (!in_gimple_form + || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) + { + tree type_domain = TYPE_DOMAIN (optype); + tree min_val = size_zero_node; + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + if (in_gimple_form + && TREE_CODE (min_val) != INTEGER_CST) + return NULL_TREE; + return build4_loc (loc, ARRAY_REF, type, op, min_val, + NULL_TREE, NULL_TREE); + } + /* *(foo *)&complexfoo => __real__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && type == TREE_TYPE (optype)) + return fold_build1_loc (loc, REALPART_EXPR, type, op); + /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */ + else if (VECTOR_TYPE_P (optype) + && type == TREE_TYPE (optype)) + { + tree part_width = TYPE_SIZE (type); + tree index = bitsize_int (0); + return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, + index); + } + } + + if (TREE_CODE (sub) == POINTER_PLUS_EXPR + && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01)) + { + tree op00 = TREE_OPERAND (sub, 0); + tree op01 = TREE_OPERAND (sub, 1); + + STRIP_NOPS (op00); + if (TREE_CODE (op00) == ADDR_EXPR) + { + tree op00type; + op00 = TREE_OPERAND (op00, 0); + op00type = TREE_TYPE (op00); + + /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ + if (VECTOR_TYPE_P (op00type) + && type == TREE_TYPE (op00type) + /* POINTER_PLUS_EXPR second operand is sizetype, unsigned, + but we want to treat offsets with MSB set as negative. + For the code below negative offsets are invalid and + TYPE_SIZE of the element is something unsigned, so + check whether op01 fits into poly_int64, which implies + it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and + then just use poly_uint64 because we want to treat the + value as unsigned. */ + && tree_fits_poly_int64_p (op01)) + { + tree part_width = TYPE_SIZE (type); + poly_uint64 max_offset + = (tree_to_uhwi (part_width) / BITS_PER_UNIT + * TYPE_VECTOR_SUBPARTS (op00type)); + if (known_lt (const_op01, max_offset)) + { + tree index = bitsize_int (const_op01 * BITS_PER_UNIT); + return fold_build3_loc (loc, + BIT_FIELD_REF, type, op00, + part_width, index); + } + } + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + else if (TREE_CODE (op00type) == COMPLEX_TYPE + && type == TREE_TYPE (op00type)) + { + if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)), + const_op01)) + return fold_build1_loc (loc, IMAGPART_EXPR, type, op00); + } + /* ((foo *)&fooarray)[1] => fooarray[1] */ + else if (TREE_CODE (op00type) == ARRAY_TYPE + && type == TREE_TYPE (op00type)) + { + tree type_domain = TYPE_DOMAIN (op00type); + tree min_val = size_zero_node; + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + poly_uint64 type_size, index; + if (poly_int_tree_p (min_val) + && poly_int_tree_p (TYPE_SIZE_UNIT (type), &type_size) + && multiple_p (const_op01, type_size, &index)) + { + poly_offset_int off = index + wi::to_poly_offset (min_val); + op01 = wide_int_to_tree (sizetype, off); + return build4_loc (loc, ARRAY_REF, type, op00, op01, + NULL_TREE, NULL_TREE); + } + } + } + } + + /* *(foo *)fooarrptr => (*fooarrptr)[0] */ + if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE + && type == TREE_TYPE (TREE_TYPE (subtype)) + && (!in_gimple_form + || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) + { + tree type_domain; + tree min_val = size_zero_node; + sub = build_fold_indirect_ref_loc (loc, sub); + type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + if (in_gimple_form + && TREE_CODE (min_val) != INTEGER_CST) + return NULL_TREE; + return build4_loc (loc, ARRAY_REF, type, sub, min_val, NULL_TREE, + NULL_TREE); + } + + return NULL_TREE; +} + +/* Builds an expression for an indirection through T, simplifying some + cases. */ + +tree +build_fold_indirect_ref_loc (location_t loc, tree t) +{ + tree type = TREE_TYPE (TREE_TYPE (t)); + tree sub = fold_indirect_ref_1 (loc, type, t); + + if (sub) + return sub; + + return build1_loc (loc, INDIRECT_REF, type, t); +} + +/* Given an INDIRECT_REF T, return either T or a simplified version. */ + +tree +fold_indirect_ref_loc (location_t loc, tree t) +{ + tree sub = fold_indirect_ref_1 (loc, TREE_TYPE (t), TREE_OPERAND (t, 0)); + + if (sub) + return sub; + else + return t; +} + +/* Strip non-trapping, non-side-effecting tree nodes from an expression + whose result is ignored. The type of the returned tree need not be + the same as the original expression. */ + +tree +fold_ignored_result (tree t) +{ + if (!TREE_SIDE_EFFECTS (t)) + return integer_zero_node; + + for (;;) + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_unary: + t = TREE_OPERAND (t, 0); + break; + + case tcc_binary: + case tcc_comparison: + if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1))) + t = TREE_OPERAND (t, 0); + else if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))) + t = TREE_OPERAND (t, 1); + else + return t; + break; + + case tcc_expression: + switch (TREE_CODE (t)) + { + case COMPOUND_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1))) + return t; + t = TREE_OPERAND (t, 0); + break; + + case COND_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) + || TREE_SIDE_EFFECTS (TREE_OPERAND (t, 2))) + return t; + t = TREE_OPERAND (t, 0); + break; + + default: + return t; + } + break; + + default: + return t; + } +} + +/* Return the value of VALUE, rounded up to a multiple of DIVISOR. */ + +tree +round_up_loc (location_t loc, tree value, unsigned int divisor) +{ + tree div = NULL_TREE; + + if (divisor == 1) + return value; + + /* See if VALUE is already a multiple of DIVISOR. If so, we don't + have to do anything. Only do this when we are not given a const, + because in that case, this check is more expensive than just + doing it. */ + if (TREE_CODE (value) != INTEGER_CST) + { + div = build_int_cst (TREE_TYPE (value), divisor); + + if (multiple_of_p (TREE_TYPE (value), value, div)) + return value; + } + + /* If divisor is a power of two, simplify this to bit manipulation. */ + if (pow2_or_zerop (divisor)) + { + if (TREE_CODE (value) == INTEGER_CST) + { + wide_int val = wi::to_wide (value); + bool overflow_p; + + if ((val & (divisor - 1)) == 0) + return value; + + overflow_p = TREE_OVERFLOW (value); + val += divisor - 1; + val &= (int) -divisor; + if (val == 0) + overflow_p = true; + + return force_fit_type (TREE_TYPE (value), val, -1, overflow_p); + } + else + { + tree t; + + t = build_int_cst (TREE_TYPE (value), divisor - 1); + value = size_binop_loc (loc, PLUS_EXPR, value, t); + t = build_int_cst (TREE_TYPE (value), - (int) divisor); + value = size_binop_loc (loc, BIT_AND_EXPR, value, t); + } + } + else + { + if (!div) + div = build_int_cst (TREE_TYPE (value), divisor); + value = size_binop_loc (loc, CEIL_DIV_EXPR, value, div); + value = size_binop_loc (loc, MULT_EXPR, value, div); + } + + return value; +} + +/* Likewise, but round down. */ + +tree +round_down_loc (location_t loc, tree value, int divisor) +{ + tree div = NULL_TREE; + + gcc_assert (divisor > 0); + if (divisor == 1) + return value; + + /* See if VALUE is already a multiple of DIVISOR. If so, we don't + have to do anything. Only do this when we are not given a const, + because in that case, this check is more expensive than just + doing it. */ + if (TREE_CODE (value) != INTEGER_CST) + { + div = build_int_cst (TREE_TYPE (value), divisor); + + if (multiple_of_p (TREE_TYPE (value), value, div)) + return value; + } + + /* If divisor is a power of two, simplify this to bit manipulation. */ + if (pow2_or_zerop (divisor)) + { + tree t; + + t = build_int_cst (TREE_TYPE (value), -divisor); + value = size_binop_loc (loc, BIT_AND_EXPR, value, t); + } + else + { + if (!div) + div = build_int_cst (TREE_TYPE (value), divisor); + value = size_binop_loc (loc, FLOOR_DIV_EXPR, value, div); + value = size_binop_loc (loc, MULT_EXPR, value, div); + } + + return value; +} + +/* Returns the pointer to the base of the object addressed by EXP and + extracts the information about the offset of the access, storing it + to PBITPOS and POFFSET. */ + +static tree +split_address_to_core_and_offset (tree exp, + poly_int64_pod *pbitpos, tree *poffset) +{ + tree core; + machine_mode mode; + int unsignedp, reversep, volatilep; + poly_int64 bitsize; + location_t loc = EXPR_LOCATION (exp); + + if (TREE_CODE (exp) == ADDR_EXPR) + { + core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos, + poffset, &mode, &unsignedp, &reversep, + &volatilep); + core = build_fold_addr_expr_loc (loc, core); + } + else if (TREE_CODE (exp) == POINTER_PLUS_EXPR) + { + core = TREE_OPERAND (exp, 0); + STRIP_NOPS (core); + *pbitpos = 0; + *poffset = TREE_OPERAND (exp, 1); + if (poly_int_tree_p (*poffset)) + { + poly_offset_int tem + = wi::sext (wi::to_poly_offset (*poffset), + TYPE_PRECISION (TREE_TYPE (*poffset))); + tem <<= LOG2_BITS_PER_UNIT; + if (tem.to_shwi (pbitpos)) + *poffset = NULL_TREE; + } + } + else + { + core = exp; + *pbitpos = 0; + *poffset = NULL_TREE; + } + + return core; +} + +/* Returns true if addresses of E1 and E2 differ by a constant, false + otherwise. If they do, E1 - E2 is stored in *DIFF. */ + +bool +ptr_difference_const (tree e1, tree e2, poly_int64_pod *diff) +{ + tree core1, core2; + poly_int64 bitpos1, bitpos2; + tree toffset1, toffset2, tdiff, type; + + core1 = split_address_to_core_and_offset (e1, &bitpos1, &toffset1); + core2 = split_address_to_core_and_offset (e2, &bitpos2, &toffset2); + + poly_int64 bytepos1, bytepos2; + if (!multiple_p (bitpos1, BITS_PER_UNIT, &bytepos1) + || !multiple_p (bitpos2, BITS_PER_UNIT, &bytepos2) + || !operand_equal_p (core1, core2, 0)) + return false; + + if (toffset1 && toffset2) + { + type = TREE_TYPE (toffset1); + if (type != TREE_TYPE (toffset2)) + toffset2 = fold_convert (type, toffset2); + + tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2); + if (!cst_and_fits_in_hwi (tdiff)) + return false; + + *diff = int_cst_value (tdiff); + } + else if (toffset1 || toffset2) + { + /* If only one of the offsets is non-constant, the difference cannot + be a constant. */ + return false; + } + else + *diff = 0; + + *diff += bytepos1 - bytepos2; + return true; +} + +/* Return OFF converted to a pointer offset type suitable as offset for + POINTER_PLUS_EXPR. Use location LOC for this conversion. */ +tree +convert_to_ptrofftype_loc (location_t loc, tree off) +{ + if (ptrofftype_p (TREE_TYPE (off))) + return off; + return fold_convert_loc (loc, sizetype, off); +} + +/* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF. */ +tree +fold_build_pointer_plus_loc (location_t loc, tree ptr, tree off) +{ + return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr), + ptr, convert_to_ptrofftype_loc (loc, off)); +} + +/* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF. */ +tree +fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off) +{ + return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr), + ptr, size_int (off)); +} + +/* Return a pointer to a NUL-terminated string containing the sequence + of bytes corresponding to the representation of the object referred to + by SRC (or a subsequence of such bytes within it if SRC is a reference + to an initialized constant array plus some constant offset). + Set *STRSIZE the number of bytes in the constant sequence including + the terminating NUL byte. *STRSIZE is equal to sizeof(A) - OFFSET + where A is the array that stores the constant sequence that SRC points + to and OFFSET is the byte offset of SRC from the beginning of A. SRC + need not point to a string or even an array of characters but may point + to an object of any type. */ + +const char * +getbyterep (tree src, unsigned HOST_WIDE_INT *strsize) +{ + /* The offset into the array A storing the string, and A's byte size. */ + tree offset_node; + tree mem_size; + + if (strsize) + *strsize = 0; + + if (strsize) + src = byte_representation (src, &offset_node, &mem_size, NULL); + else + src = string_constant (src, &offset_node, &mem_size, NULL); + if (!src) + return NULL; + + unsigned HOST_WIDE_INT offset = 0; + if (offset_node != NULL_TREE) + { + if (!tree_fits_uhwi_p (offset_node)) + return NULL; + else + offset = tree_to_uhwi (offset_node); + } + + if (!tree_fits_uhwi_p (mem_size)) + return NULL; + + /* ARRAY_SIZE is the byte size of the array the constant sequence + is stored in and equal to sizeof A. INIT_BYTES is the number + of bytes in the constant sequence used to initialize the array, + including any embedded NULs as well as the terminating NUL (for + strings), but not including any trailing zeros/NULs past + the terminating one appended implicitly to a string literal to + zero out the remainder of the array it's stored in. For example, + given: + const char a[7] = "abc\0d"; + n = strlen (a + 1); + ARRAY_SIZE is 7, INIT_BYTES is 6, and OFFSET is 1. For a valid + (i.e., nul-terminated) string with no embedded nuls, INIT_BYTES + is equal to strlen (A) + 1. */ + const unsigned HOST_WIDE_INT array_size = tree_to_uhwi (mem_size); + unsigned HOST_WIDE_INT init_bytes = TREE_STRING_LENGTH (src); + const char *string = TREE_STRING_POINTER (src); + + /* Ideally this would turn into a gcc_checking_assert over time. */ + if (init_bytes > array_size) + init_bytes = array_size; + + if (init_bytes == 0 || offset >= array_size) + return NULL; + + if (strsize) + { + /* Compute and store the number of characters from the beginning + of the substring at OFFSET to the end, including the terminating + nul. Offsets past the initial length refer to null strings. */ + if (offset < init_bytes) + *strsize = init_bytes - offset; + else + *strsize = 1; + } + else + { + tree eltype = TREE_TYPE (TREE_TYPE (src)); + /* Support only properly NUL-terminated single byte strings. */ + if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1) + return NULL; + if (string[init_bytes - 1] != '\0') + return NULL; + } + + return offset < init_bytes ? string + offset : ""; +} + +/* Return a pointer to a NUL-terminated string corresponding to + the expression STR referencing a constant string, possibly + involving a constant offset. Return null if STR either doesn't + reference a constant string or if it involves a nonconstant + offset. */ + +const char * +c_getstr (tree str) +{ + return getbyterep (str, NULL); +} + +/* Given a tree T, compute which bits in T may be nonzero. */ + +wide_int +tree_nonzero_bits (const_tree t) +{ + switch (TREE_CODE (t)) + { + case INTEGER_CST: + return wi::to_wide (t); + case SSA_NAME: + return get_nonzero_bits (t); + case NON_LVALUE_EXPR: + case SAVE_EXPR: + return tree_nonzero_bits (TREE_OPERAND (t, 0)); + case BIT_AND_EXPR: + return wi::bit_and (tree_nonzero_bits (TREE_OPERAND (t, 0)), + tree_nonzero_bits (TREE_OPERAND (t, 1))); + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + return wi::bit_or (tree_nonzero_bits (TREE_OPERAND (t, 0)), + tree_nonzero_bits (TREE_OPERAND (t, 1))); + case COND_EXPR: + return wi::bit_or (tree_nonzero_bits (TREE_OPERAND (t, 1)), + tree_nonzero_bits (TREE_OPERAND (t, 2))); + CASE_CONVERT: + return wide_int::from (tree_nonzero_bits (TREE_OPERAND (t, 0)), + TYPE_PRECISION (TREE_TYPE (t)), + TYPE_SIGN (TREE_TYPE (TREE_OPERAND (t, 0)))); + case PLUS_EXPR: + if (INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + wide_int nzbits1 = tree_nonzero_bits (TREE_OPERAND (t, 0)); + wide_int nzbits2 = tree_nonzero_bits (TREE_OPERAND (t, 1)); + if (wi::bit_and (nzbits1, nzbits2) == 0) + return wi::bit_or (nzbits1, nzbits2); + } + break; + case LSHIFT_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree type = TREE_TYPE (t); + wide_int nzbits = tree_nonzero_bits (TREE_OPERAND (t, 0)); + wide_int arg1 = wi::to_wide (TREE_OPERAND (t, 1), + TYPE_PRECISION (type)); + return wi::neg_p (arg1) + ? wi::rshift (nzbits, -arg1, TYPE_SIGN (type)) + : wi::lshift (nzbits, arg1); + } + break; + case RSHIFT_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree type = TREE_TYPE (t); + wide_int nzbits = tree_nonzero_bits (TREE_OPERAND (t, 0)); + wide_int arg1 = wi::to_wide (TREE_OPERAND (t, 1), + TYPE_PRECISION (type)); + return wi::neg_p (arg1) + ? wi::lshift (nzbits, -arg1) + : wi::rshift (nzbits, arg1, TYPE_SIGN (type)); + } + break; + default: + break; + } + + return wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (t))); +} + +/* Helper function for address compare simplifications in match.pd. + OP0 and OP1 are ADDR_EXPR operands being compared by CODE. + BASE0, BASE1, OFF0 and OFF1 are set by the function. + GENERIC is true if GENERIC folding and false for GIMPLE folding. + Returns 0 if OP0 is known to be unequal to OP1 regardless of OFF{0,1}, + 1 if bases are known to be equal and OP0 cmp OP1 depends on OFF0 cmp OFF1, + and 2 if unknown. */ + +int +address_compare (tree_code code, tree type, tree op0, tree op1, + tree &base0, tree &base1, poly_int64 &off0, poly_int64 &off1, + bool generic) +{ + gcc_checking_assert (TREE_CODE (op0) == ADDR_EXPR); + gcc_checking_assert (TREE_CODE (op1) == ADDR_EXPR); + base0 = get_addr_base_and_unit_offset (TREE_OPERAND (op0, 0), &off0); + base1 = get_addr_base_and_unit_offset (TREE_OPERAND (op1, 0), &off1); + if (base0 && TREE_CODE (base0) == MEM_REF) + { + off0 += mem_ref_offset (base0).force_shwi (); + base0 = TREE_OPERAND (base0, 0); + } + if (base1 && TREE_CODE (base1) == MEM_REF) + { + off1 += mem_ref_offset (base1).force_shwi (); + base1 = TREE_OPERAND (base1, 0); + } + if (base0 == NULL_TREE || base1 == NULL_TREE) + return 2; + + int equal = 2; + /* Punt in GENERIC on variables with value expressions; + the value expressions might point to fields/elements + of other vars etc. */ + if (generic + && ((VAR_P (base0) && DECL_HAS_VALUE_EXPR_P (base0)) + || (VAR_P (base1) && DECL_HAS_VALUE_EXPR_P (base1)))) + return 2; + else if (decl_in_symtab_p (base0) && decl_in_symtab_p (base1)) + { + symtab_node *node0 = symtab_node::get_create (base0); + symtab_node *node1 = symtab_node::get_create (base1); + equal = node0->equal_address_to (node1); + } + else if ((DECL_P (base0) + || TREE_CODE (base0) == SSA_NAME + || TREE_CODE (base0) == STRING_CST) + && (DECL_P (base1) + || TREE_CODE (base1) == SSA_NAME + || TREE_CODE (base1) == STRING_CST)) + equal = (base0 == base1); + if (equal == 1) + { + if (code == EQ_EXPR + || code == NE_EXPR + /* If the offsets are equal we can ignore overflow. */ + || known_eq (off0, off1) + || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)) + /* Or if we compare using pointers to decls or strings. */ + || (POINTER_TYPE_P (type) + && (DECL_P (base0) || TREE_CODE (base0) == STRING_CST))) + return 1; + return 2; + } + if (equal != 0) + return equal; + if (code != EQ_EXPR && code != NE_EXPR) + return 2; + + HOST_WIDE_INT ioff0 = -1, ioff1 = -1; + off0.is_constant (&ioff0); + off1.is_constant (&ioff1); + if ((DECL_P (base0) && TREE_CODE (base1) == STRING_CST) + || (TREE_CODE (base0) == STRING_CST && DECL_P (base1)) + || (TREE_CODE (base0) == STRING_CST + && TREE_CODE (base1) == STRING_CST + && ioff0 >= 0 && ioff1 >= 0 + && ioff0 < TREE_STRING_LENGTH (base0) + && ioff1 < TREE_STRING_LENGTH (base1) + /* This is a too conservative test that the STRING_CSTs + will not end up being string-merged. */ + && strncmp (TREE_STRING_POINTER (base0) + ioff0, + TREE_STRING_POINTER (base1) + ioff1, + MIN (TREE_STRING_LENGTH (base0) - ioff0, + TREE_STRING_LENGTH (base1) - ioff1)) != 0)) + ; + else if (!DECL_P (base0) || !DECL_P (base1)) + return 2; + /* If this is a pointer comparison, ignore for now even + valid equalities where one pointer is the offset zero + of one object and the other to one past end of another one. */ + else if (!folding_initializer && !INTEGRAL_TYPE_P (type)) + ; + /* Assume that automatic variables can't be adjacent to global + variables. */ + else if (is_global_var (base0) != is_global_var (base1)) + ; + else + { + tree sz0 = DECL_SIZE_UNIT (base0); + tree sz1 = DECL_SIZE_UNIT (base1); + /* If sizes are unknown, e.g. VLA or not representable, punt. */ + if (!tree_fits_poly_int64_p (sz0) || !tree_fits_poly_int64_p (sz1)) + return 2; + + poly_int64 size0 = tree_to_poly_int64 (sz0); + poly_int64 size1 = tree_to_poly_int64 (sz1); + /* If one offset is pointing (or could be) to the beginning of one + object and the other is pointing to one past the last byte of the + other object, punt. */ + if (maybe_eq (off0, 0) && maybe_eq (off1, size1)) + equal = 2; + else if (maybe_eq (off1, 0) && maybe_eq (off0, size0)) + equal = 2; + /* If both offsets are the same, there are some cases we know that are + ok. Either if we know they aren't zero, or if we know both sizes + are no zero. */ + if (equal == 2 + && known_eq (off0, off1) + && (known_ne (off0, 0) + || (known_ne (size0, 0) && known_ne (size1, 0)))) + equal = 0; + } + return equal; +} + +#if CHECKING_P + +namespace selftest { + +/* Helper functions for writing tests of folding trees. */ + +/* Verify that the binary op (LHS CODE RHS) folds to CONSTANT. */ + +static void +assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs, + tree constant) +{ + ASSERT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs)); +} + +/* Verify that the binary op (LHS CODE RHS) folds to an NON_LVALUE_EXPR + wrapping WRAPPED_EXPR. */ + +static void +assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs, + tree wrapped_expr) +{ + tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs); + ASSERT_NE (wrapped_expr, result); + ASSERT_EQ (NON_LVALUE_EXPR, TREE_CODE (result)); + ASSERT_EQ (wrapped_expr, TREE_OPERAND (result, 0)); +} + +/* Verify that various arithmetic binary operations are folded + correctly. */ + +static void +test_arithmetic_folding () +{ + tree type = integer_type_node; + tree x = create_tmp_var_raw (type, "x"); + tree zero = build_zero_cst (type); + tree one = build_int_cst (type, 1); + + /* Addition. */ + /* 1 <-- (0 + 1) */ + assert_binop_folds_to_const (zero, PLUS_EXPR, one, + one); + assert_binop_folds_to_const (one, PLUS_EXPR, zero, + one); + + /* (nonlvalue)x <-- (x + 0) */ + assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero, + x); + + /* Subtraction. */ + /* 0 <-- (x - x) */ + assert_binop_folds_to_const (x, MINUS_EXPR, x, + zero); + assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero, + x); + + /* Multiplication. */ + /* 0 <-- (x * 0) */ + assert_binop_folds_to_const (x, MULT_EXPR, zero, + zero); + + /* (nonlvalue)x <-- (x * 1) */ + assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one, + x); +} + +/* Verify that various binary operations on vectors are folded + correctly. */ + +static void +test_vector_folding () +{ + tree inner_type = integer_type_node; + tree type = build_vector_type (inner_type, 4); + tree zero = build_zero_cst (type); + tree one = build_one_cst (type); + tree index = build_index_vector (type, 0, 1); + + /* Verify equality tests that return a scalar boolean result. */ + tree res_type = boolean_type_node; + ASSERT_FALSE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, zero, one))); + ASSERT_TRUE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, zero, zero))); + ASSERT_TRUE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, zero, one))); + ASSERT_FALSE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, one, one))); + ASSERT_TRUE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, index, one))); + ASSERT_FALSE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, + index, one))); + ASSERT_FALSE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, + index, index))); + ASSERT_TRUE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, + index, index))); +} + +/* Verify folding of VEC_DUPLICATE_EXPRs. */ + +static void +test_vec_duplicate_folding () +{ + scalar_int_mode int_mode = SCALAR_INT_TYPE_MODE (ssizetype); + machine_mode vec_mode = targetm.vectorize.preferred_simd_mode (int_mode); + /* This will be 1 if VEC_MODE isn't a vector mode. */ + poly_uint64 nunits = GET_MODE_NUNITS (vec_mode); + + tree type = build_vector_type (ssizetype, nunits); + tree dup5_expr = fold_unary (VEC_DUPLICATE_EXPR, type, ssize_int (5)); + tree dup5_cst = build_vector_from_val (type, ssize_int (5)); + ASSERT_TRUE (operand_equal_p (dup5_expr, dup5_cst, 0)); +} + +/* Run all of the selftests within this file. */ + +void +fold_const_c_tests () +{ + test_arithmetic_folding (); + test_vector_folding (); + test_vec_duplicate_folding (); +} + +} // namespace selftest + +#endif /* CHECKING_P */ |