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/gimplify.c | |
parent | 490e23032baaece71f2ec09fa1805064b150fbc2 (diff) | |
download | gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2 |
Rename .c files to .cc files.
gcc/ada/ChangeLog:
* adadecode.c: Moved to...
* adadecode.cc: ...here.
* affinity.c: Moved to...
* affinity.cc: ...here.
* argv-lynxos178-raven-cert.c: Moved to...
* argv-lynxos178-raven-cert.cc: ...here.
* argv.c: Moved to...
* argv.cc: ...here.
* aux-io.c: Moved to...
* aux-io.cc: ...here.
* cio.c: Moved to...
* cio.cc: ...here.
* cstreams.c: Moved to...
* cstreams.cc: ...here.
* env.c: Moved to...
* env.cc: ...here.
* exit.c: Moved to...
* exit.cc: ...here.
* expect.c: Moved to...
* expect.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* gcc-interface/cuintp.c: Moved to...
* gcc-interface/cuintp.cc: ...here.
* gcc-interface/decl.c: Moved to...
* gcc-interface/decl.cc: ...here.
* gcc-interface/misc.c: Moved to...
* gcc-interface/misc.cc: ...here.
* gcc-interface/targtyps.c: Moved to...
* gcc-interface/targtyps.cc: ...here.
* gcc-interface/trans.c: Moved to...
* gcc-interface/trans.cc: ...here.
* gcc-interface/utils.c: Moved to...
* gcc-interface/utils.cc: ...here.
* gcc-interface/utils2.c: Moved to...
* gcc-interface/utils2.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* initialize.c: Moved to...
* initialize.cc: ...here.
* libgnarl/thread.c: Moved to...
* libgnarl/thread.cc: ...here.
* link.c: Moved to...
* link.cc: ...here.
* locales.c: Moved to...
* locales.cc: ...here.
* mkdir.c: Moved to...
* mkdir.cc: ...here.
* raise.c: Moved to...
* raise.cc: ...here.
* rtfinal.c: Moved to...
* rtfinal.cc: ...here.
* rtinit.c: Moved to...
* rtinit.cc: ...here.
* seh_init.c: Moved to...
* seh_init.cc: ...here.
* sigtramp-armdroid.c: Moved to...
* sigtramp-armdroid.cc: ...here.
* sigtramp-ios.c: Moved to...
* sigtramp-ios.cc: ...here.
* sigtramp-qnx.c: Moved to...
* sigtramp-qnx.cc: ...here.
* sigtramp-vxworks.c: Moved to...
* sigtramp-vxworks.cc: ...here.
* socket.c: Moved to...
* socket.cc: ...here.
* tracebak.c: Moved to...
* tracebak.cc: ...here.
* version.c: Moved to...
* version.cc: ...here.
* vx_stack_info.c: Moved to...
* vx_stack_info.cc: ...here.
gcc/ChangeLog:
* adjust-alignment.c: Moved to...
* adjust-alignment.cc: ...here.
* alias.c: Moved to...
* alias.cc: ...here.
* alloc-pool.c: Moved to...
* alloc-pool.cc: ...here.
* asan.c: Moved to...
* asan.cc: ...here.
* attribs.c: Moved to...
* attribs.cc: ...here.
* auto-inc-dec.c: Moved to...
* auto-inc-dec.cc: ...here.
* auto-profile.c: Moved to...
* auto-profile.cc: ...here.
* bb-reorder.c: Moved to...
* bb-reorder.cc: ...here.
* bitmap.c: Moved to...
* bitmap.cc: ...here.
* btfout.c: Moved to...
* btfout.cc: ...here.
* builtins.c: Moved to...
* builtins.cc: ...here.
* caller-save.c: Moved to...
* caller-save.cc: ...here.
* calls.c: Moved to...
* calls.cc: ...here.
* ccmp.c: Moved to...
* ccmp.cc: ...here.
* cfg.c: Moved to...
* cfg.cc: ...here.
* cfganal.c: Moved to...
* cfganal.cc: ...here.
* cfgbuild.c: Moved to...
* cfgbuild.cc: ...here.
* cfgcleanup.c: Moved to...
* cfgcleanup.cc: ...here.
* cfgexpand.c: Moved to...
* cfgexpand.cc: ...here.
* cfghooks.c: Moved to...
* cfghooks.cc: ...here.
* cfgloop.c: Moved to...
* cfgloop.cc: ...here.
* cfgloopanal.c: Moved to...
* cfgloopanal.cc: ...here.
* cfgloopmanip.c: Moved to...
* cfgloopmanip.cc: ...here.
* cfgrtl.c: Moved to...
* cfgrtl.cc: ...here.
* cgraph.c: Moved to...
* cgraph.cc: ...here.
* cgraphbuild.c: Moved to...
* cgraphbuild.cc: ...here.
* cgraphclones.c: Moved to...
* cgraphclones.cc: ...here.
* cgraphunit.c: Moved to...
* cgraphunit.cc: ...here.
* collect-utils.c: Moved to...
* collect-utils.cc: ...here.
* collect2-aix.c: Moved to...
* collect2-aix.cc: ...here.
* collect2.c: Moved to...
* collect2.cc: ...here.
* combine-stack-adj.c: Moved to...
* combine-stack-adj.cc: ...here.
* combine.c: Moved to...
* combine.cc: ...here.
* common/common-targhooks.c: Moved to...
* common/common-targhooks.cc: ...here.
* common/config/aarch64/aarch64-common.c: Moved to...
* common/config/aarch64/aarch64-common.cc: ...here.
* common/config/alpha/alpha-common.c: Moved to...
* common/config/alpha/alpha-common.cc: ...here.
* common/config/arc/arc-common.c: Moved to...
* common/config/arc/arc-common.cc: ...here.
* common/config/arm/arm-common.c: Moved to...
* common/config/arm/arm-common.cc: ...here.
* common/config/avr/avr-common.c: Moved to...
* common/config/avr/avr-common.cc: ...here.
* common/config/bfin/bfin-common.c: Moved to...
* common/config/bfin/bfin-common.cc: ...here.
* common/config/bpf/bpf-common.c: Moved to...
* common/config/bpf/bpf-common.cc: ...here.
* common/config/c6x/c6x-common.c: Moved to...
* common/config/c6x/c6x-common.cc: ...here.
* common/config/cr16/cr16-common.c: Moved to...
* common/config/cr16/cr16-common.cc: ...here.
* common/config/cris/cris-common.c: Moved to...
* common/config/cris/cris-common.cc: ...here.
* common/config/csky/csky-common.c: Moved to...
* common/config/csky/csky-common.cc: ...here.
* common/config/default-common.c: Moved to...
* common/config/default-common.cc: ...here.
* common/config/epiphany/epiphany-common.c: Moved to...
* common/config/epiphany/epiphany-common.cc: ...here.
* common/config/fr30/fr30-common.c: Moved to...
* common/config/fr30/fr30-common.cc: ...here.
* common/config/frv/frv-common.c: Moved to...
* common/config/frv/frv-common.cc: ...here.
* common/config/gcn/gcn-common.c: Moved to...
* common/config/gcn/gcn-common.cc: ...here.
* common/config/h8300/h8300-common.c: Moved to...
* common/config/h8300/h8300-common.cc: ...here.
* common/config/i386/i386-common.c: Moved to...
* common/config/i386/i386-common.cc: ...here.
* common/config/ia64/ia64-common.c: Moved to...
* common/config/ia64/ia64-common.cc: ...here.
* common/config/iq2000/iq2000-common.c: Moved to...
* common/config/iq2000/iq2000-common.cc: ...here.
* common/config/lm32/lm32-common.c: Moved to...
* common/config/lm32/lm32-common.cc: ...here.
* common/config/m32r/m32r-common.c: Moved to...
* common/config/m32r/m32r-common.cc: ...here.
* common/config/m68k/m68k-common.c: Moved to...
* common/config/m68k/m68k-common.cc: ...here.
* common/config/mcore/mcore-common.c: Moved to...
* common/config/mcore/mcore-common.cc: ...here.
* common/config/microblaze/microblaze-common.c: Moved to...
* common/config/microblaze/microblaze-common.cc: ...here.
* common/config/mips/mips-common.c: Moved to...
* common/config/mips/mips-common.cc: ...here.
* common/config/mmix/mmix-common.c: Moved to...
* common/config/mmix/mmix-common.cc: ...here.
* common/config/mn10300/mn10300-common.c: Moved to...
* common/config/mn10300/mn10300-common.cc: ...here.
* common/config/msp430/msp430-common.c: Moved to...
* common/config/msp430/msp430-common.cc: ...here.
* common/config/nds32/nds32-common.c: Moved to...
* common/config/nds32/nds32-common.cc: ...here.
* common/config/nios2/nios2-common.c: Moved to...
* common/config/nios2/nios2-common.cc: ...here.
* common/config/nvptx/nvptx-common.c: Moved to...
* common/config/nvptx/nvptx-common.cc: ...here.
* common/config/or1k/or1k-common.c: Moved to...
* common/config/or1k/or1k-common.cc: ...here.
* common/config/pa/pa-common.c: Moved to...
* common/config/pa/pa-common.cc: ...here.
* common/config/pdp11/pdp11-common.c: Moved to...
* common/config/pdp11/pdp11-common.cc: ...here.
* common/config/pru/pru-common.c: Moved to...
* common/config/pru/pru-common.cc: ...here.
* common/config/riscv/riscv-common.c: Moved to...
* common/config/riscv/riscv-common.cc: ...here.
* common/config/rs6000/rs6000-common.c: Moved to...
* common/config/rs6000/rs6000-common.cc: ...here.
* common/config/rx/rx-common.c: Moved to...
* common/config/rx/rx-common.cc: ...here.
* common/config/s390/s390-common.c: Moved to...
* common/config/s390/s390-common.cc: ...here.
* common/config/sh/sh-common.c: Moved to...
* common/config/sh/sh-common.cc: ...here.
* common/config/sparc/sparc-common.c: Moved to...
* common/config/sparc/sparc-common.cc: ...here.
* common/config/tilegx/tilegx-common.c: Moved to...
* common/config/tilegx/tilegx-common.cc: ...here.
* common/config/tilepro/tilepro-common.c: Moved to...
* common/config/tilepro/tilepro-common.cc: ...here.
* common/config/v850/v850-common.c: Moved to...
* common/config/v850/v850-common.cc: ...here.
* common/config/vax/vax-common.c: Moved to...
* common/config/vax/vax-common.cc: ...here.
* common/config/visium/visium-common.c: Moved to...
* common/config/visium/visium-common.cc: ...here.
* common/config/xstormy16/xstormy16-common.c: Moved to...
* common/config/xstormy16/xstormy16-common.cc: ...here.
* common/config/xtensa/xtensa-common.c: Moved to...
* common/config/xtensa/xtensa-common.cc: ...here.
* compare-elim.c: Moved to...
* compare-elim.cc: ...here.
* config/aarch64/aarch64-bti-insert.c: Moved to...
* config/aarch64/aarch64-bti-insert.cc: ...here.
* config/aarch64/aarch64-builtins.c: Moved to...
* config/aarch64/aarch64-builtins.cc: ...here.
* config/aarch64/aarch64-c.c: Moved to...
* config/aarch64/aarch64-c.cc: ...here.
* config/aarch64/aarch64-d.c: Moved to...
* config/aarch64/aarch64-d.cc: ...here.
* config/aarch64/aarch64.c: Moved to...
* config/aarch64/aarch64.cc: ...here.
* config/aarch64/cortex-a57-fma-steering.c: Moved to...
* config/aarch64/cortex-a57-fma-steering.cc: ...here.
* config/aarch64/driver-aarch64.c: Moved to...
* config/aarch64/driver-aarch64.cc: ...here.
* config/aarch64/falkor-tag-collision-avoidance.c: Moved to...
* config/aarch64/falkor-tag-collision-avoidance.cc: ...here.
* config/aarch64/host-aarch64-darwin.c: Moved to...
* config/aarch64/host-aarch64-darwin.cc: ...here.
* config/alpha/alpha.c: Moved to...
* config/alpha/alpha.cc: ...here.
* config/alpha/driver-alpha.c: Moved to...
* config/alpha/driver-alpha.cc: ...here.
* config/arc/arc-c.c: Moved to...
* config/arc/arc-c.cc: ...here.
* config/arc/arc.c: Moved to...
* config/arc/arc.cc: ...here.
* config/arc/driver-arc.c: Moved to...
* config/arc/driver-arc.cc: ...here.
* config/arm/aarch-common.c: Moved to...
* config/arm/aarch-common.cc: ...here.
* config/arm/arm-builtins.c: Moved to...
* config/arm/arm-builtins.cc: ...here.
* config/arm/arm-c.c: Moved to...
* config/arm/arm-c.cc: ...here.
* config/arm/arm-d.c: Moved to...
* config/arm/arm-d.cc: ...here.
* config/arm/arm.c: Moved to...
* config/arm/arm.cc: ...here.
* config/arm/driver-arm.c: Moved to...
* config/arm/driver-arm.cc: ...here.
* config/avr/avr-c.c: Moved to...
* config/avr/avr-c.cc: ...here.
* config/avr/avr-devices.c: Moved to...
* config/avr/avr-devices.cc: ...here.
* config/avr/avr-log.c: Moved to...
* config/avr/avr-log.cc: ...here.
* config/avr/avr.c: Moved to...
* config/avr/avr.cc: ...here.
* config/avr/driver-avr.c: Moved to...
* config/avr/driver-avr.cc: ...here.
* config/avr/gen-avr-mmcu-specs.c: Moved to...
* config/avr/gen-avr-mmcu-specs.cc: ...here.
* config/avr/gen-avr-mmcu-texi.c: Moved to...
* config/avr/gen-avr-mmcu-texi.cc: ...here.
* config/bfin/bfin.c: Moved to...
* config/bfin/bfin.cc: ...here.
* config/bpf/bpf.c: Moved to...
* config/bpf/bpf.cc: ...here.
* config/bpf/coreout.c: Moved to...
* config/bpf/coreout.cc: ...here.
* config/c6x/c6x.c: Moved to...
* config/c6x/c6x.cc: ...here.
* config/cr16/cr16.c: Moved to...
* config/cr16/cr16.cc: ...here.
* config/cris/cris.c: Moved to...
* config/cris/cris.cc: ...here.
* config/csky/csky.c: Moved to...
* config/csky/csky.cc: ...here.
* config/darwin-c.c: Moved to...
* config/darwin-c.cc: ...here.
* config/darwin-d.c: Moved to...
* config/darwin-d.cc: ...here.
* config/darwin-driver.c: Moved to...
* config/darwin-driver.cc: ...here.
* config/darwin-f.c: Moved to...
* config/darwin-f.cc: ...here.
* config/darwin.c: Moved to...
* config/darwin.cc: ...here.
* config/default-c.c: Moved to...
* config/default-c.cc: ...here.
* config/default-d.c: Moved to...
* config/default-d.cc: ...here.
* config/dragonfly-d.c: Moved to...
* config/dragonfly-d.cc: ...here.
* config/epiphany/epiphany.c: Moved to...
* config/epiphany/epiphany.cc: ...here.
* config/epiphany/mode-switch-use.c: Moved to...
* config/epiphany/mode-switch-use.cc: ...here.
* config/epiphany/resolve-sw-modes.c: Moved to...
* config/epiphany/resolve-sw-modes.cc: ...here.
* config/fr30/fr30.c: Moved to...
* config/fr30/fr30.cc: ...here.
* config/freebsd-d.c: Moved to...
* config/freebsd-d.cc: ...here.
* config/frv/frv.c: Moved to...
* config/frv/frv.cc: ...here.
* config/ft32/ft32.c: Moved to...
* config/ft32/ft32.cc: ...here.
* config/gcn/driver-gcn.c: Moved to...
* config/gcn/driver-gcn.cc: ...here.
* config/gcn/gcn-run.c: Moved to...
* config/gcn/gcn-run.cc: ...here.
* config/gcn/gcn-tree.c: Moved to...
* config/gcn/gcn-tree.cc: ...here.
* config/gcn/gcn.c: Moved to...
* config/gcn/gcn.cc: ...here.
* config/gcn/mkoffload.c: Moved to...
* config/gcn/mkoffload.cc: ...here.
* config/glibc-c.c: Moved to...
* config/glibc-c.cc: ...here.
* config/glibc-d.c: Moved to...
* config/glibc-d.cc: ...here.
* config/h8300/h8300.c: Moved to...
* config/h8300/h8300.cc: ...here.
* config/host-darwin.c: Moved to...
* config/host-darwin.cc: ...here.
* config/host-hpux.c: Moved to...
* config/host-hpux.cc: ...here.
* config/host-linux.c: Moved to...
* config/host-linux.cc: ...here.
* config/host-netbsd.c: Moved to...
* config/host-netbsd.cc: ...here.
* config/host-openbsd.c: Moved to...
* config/host-openbsd.cc: ...here.
* config/host-solaris.c: Moved to...
* config/host-solaris.cc: ...here.
* config/i386/djgpp.c: Moved to...
* config/i386/djgpp.cc: ...here.
* config/i386/driver-i386.c: Moved to...
* config/i386/driver-i386.cc: ...here.
* config/i386/driver-mingw32.c: Moved to...
* config/i386/driver-mingw32.cc: ...here.
* config/i386/gnu-property.c: Moved to...
* config/i386/gnu-property.cc: ...here.
* config/i386/host-cygwin.c: Moved to...
* config/i386/host-cygwin.cc: ...here.
* config/i386/host-i386-darwin.c: Moved to...
* config/i386/host-i386-darwin.cc: ...here.
* config/i386/host-mingw32.c: Moved to...
* config/i386/host-mingw32.cc: ...here.
* config/i386/i386-builtins.c: Moved to...
* config/i386/i386-builtins.cc: ...here.
* config/i386/i386-c.c: Moved to...
* config/i386/i386-c.cc: ...here.
* config/i386/i386-d.c: Moved to...
* config/i386/i386-d.cc: ...here.
* config/i386/i386-expand.c: Moved to...
* config/i386/i386-expand.cc: ...here.
* config/i386/i386-features.c: Moved to...
* config/i386/i386-features.cc: ...here.
* config/i386/i386-options.c: Moved to...
* config/i386/i386-options.cc: ...here.
* config/i386/i386.c: Moved to...
* config/i386/i386.cc: ...here.
* config/i386/intelmic-mkoffload.c: Moved to...
* config/i386/intelmic-mkoffload.cc: ...here.
* config/i386/msformat-c.c: Moved to...
* config/i386/msformat-c.cc: ...here.
* config/i386/winnt-cxx.c: Moved to...
* config/i386/winnt-cxx.cc: ...here.
* config/i386/winnt-d.c: Moved to...
* config/i386/winnt-d.cc: ...here.
* config/i386/winnt-stubs.c: Moved to...
* config/i386/winnt-stubs.cc: ...here.
* config/i386/winnt.c: Moved to...
* config/i386/winnt.cc: ...here.
* config/i386/x86-tune-sched-atom.c: Moved to...
* config/i386/x86-tune-sched-atom.cc: ...here.
* config/i386/x86-tune-sched-bd.c: Moved to...
* config/i386/x86-tune-sched-bd.cc: ...here.
* config/i386/x86-tune-sched-core.c: Moved to...
* config/i386/x86-tune-sched-core.cc: ...here.
* config/i386/x86-tune-sched.c: Moved to...
* config/i386/x86-tune-sched.cc: ...here.
* config/ia64/ia64-c.c: Moved to...
* config/ia64/ia64-c.cc: ...here.
* config/ia64/ia64.c: Moved to...
* config/ia64/ia64.cc: ...here.
* config/iq2000/iq2000.c: Moved to...
* config/iq2000/iq2000.cc: ...here.
* config/linux.c: Moved to...
* config/linux.cc: ...here.
* config/lm32/lm32.c: Moved to...
* config/lm32/lm32.cc: ...here.
* config/m32c/m32c-pragma.c: Moved to...
* config/m32c/m32c-pragma.cc: ...here.
* config/m32c/m32c.c: Moved to...
* config/m32c/m32c.cc: ...here.
* config/m32r/m32r.c: Moved to...
* config/m32r/m32r.cc: ...here.
* config/m68k/m68k.c: Moved to...
* config/m68k/m68k.cc: ...here.
* config/mcore/mcore.c: Moved to...
* config/mcore/mcore.cc: ...here.
* config/microblaze/microblaze-c.c: Moved to...
* config/microblaze/microblaze-c.cc: ...here.
* config/microblaze/microblaze.c: Moved to...
* config/microblaze/microblaze.cc: ...here.
* config/mips/driver-native.c: Moved to...
* config/mips/driver-native.cc: ...here.
* config/mips/frame-header-opt.c: Moved to...
* config/mips/frame-header-opt.cc: ...here.
* config/mips/mips-d.c: Moved to...
* config/mips/mips-d.cc: ...here.
* config/mips/mips.c: Moved to...
* config/mips/mips.cc: ...here.
* config/mmix/mmix.c: Moved to...
* config/mmix/mmix.cc: ...here.
* config/mn10300/mn10300.c: Moved to...
* config/mn10300/mn10300.cc: ...here.
* config/moxie/moxie.c: Moved to...
* config/moxie/moxie.cc: ...here.
* config/msp430/driver-msp430.c: Moved to...
* config/msp430/driver-msp430.cc: ...here.
* config/msp430/msp430-c.c: Moved to...
* config/msp430/msp430-c.cc: ...here.
* config/msp430/msp430-devices.c: Moved to...
* config/msp430/msp430-devices.cc: ...here.
* config/msp430/msp430.c: Moved to...
* config/msp430/msp430.cc: ...here.
* config/nds32/nds32-cost.c: Moved to...
* config/nds32/nds32-cost.cc: ...here.
* config/nds32/nds32-fp-as-gp.c: Moved to...
* config/nds32/nds32-fp-as-gp.cc: ...here.
* config/nds32/nds32-intrinsic.c: Moved to...
* config/nds32/nds32-intrinsic.cc: ...here.
* config/nds32/nds32-isr.c: Moved to...
* config/nds32/nds32-isr.cc: ...here.
* config/nds32/nds32-md-auxiliary.c: Moved to...
* config/nds32/nds32-md-auxiliary.cc: ...here.
* config/nds32/nds32-memory-manipulation.c: Moved to...
* config/nds32/nds32-memory-manipulation.cc: ...here.
* config/nds32/nds32-pipelines-auxiliary.c: Moved to...
* config/nds32/nds32-pipelines-auxiliary.cc: ...here.
* config/nds32/nds32-predicates.c: Moved to...
* config/nds32/nds32-predicates.cc: ...here.
* config/nds32/nds32-relax-opt.c: Moved to...
* config/nds32/nds32-relax-opt.cc: ...here.
* config/nds32/nds32-utils.c: Moved to...
* config/nds32/nds32-utils.cc: ...here.
* config/nds32/nds32.c: Moved to...
* config/nds32/nds32.cc: ...here.
* config/netbsd-d.c: Moved to...
* config/netbsd-d.cc: ...here.
* config/netbsd.c: Moved to...
* config/netbsd.cc: ...here.
* config/nios2/nios2.c: Moved to...
* config/nios2/nios2.cc: ...here.
* config/nvptx/mkoffload.c: Moved to...
* config/nvptx/mkoffload.cc: ...here.
* config/nvptx/nvptx-c.c: Moved to...
* config/nvptx/nvptx-c.cc: ...here.
* config/nvptx/nvptx.c: Moved to...
* config/nvptx/nvptx.cc: ...here.
* config/openbsd-d.c: Moved to...
* config/openbsd-d.cc: ...here.
* config/or1k/or1k.c: Moved to...
* config/or1k/or1k.cc: ...here.
* config/pa/pa-d.c: Moved to...
* config/pa/pa-d.cc: ...here.
* config/pa/pa.c: Moved to...
* config/pa/pa.cc: ...here.
* config/pdp11/pdp11.c: Moved to...
* config/pdp11/pdp11.cc: ...here.
* config/pru/pru-passes.c: Moved to...
* config/pru/pru-passes.cc: ...here.
* config/pru/pru-pragma.c: Moved to...
* config/pru/pru-pragma.cc: ...here.
* config/pru/pru.c: Moved to...
* config/pru/pru.cc: ...here.
* config/riscv/riscv-builtins.c: Moved to...
* config/riscv/riscv-builtins.cc: ...here.
* config/riscv/riscv-c.c: Moved to...
* config/riscv/riscv-c.cc: ...here.
* config/riscv/riscv-d.c: Moved to...
* config/riscv/riscv-d.cc: ...here.
* config/riscv/riscv-shorten-memrefs.c: Moved to...
* config/riscv/riscv-shorten-memrefs.cc: ...here.
* config/riscv/riscv-sr.c: Moved to...
* config/riscv/riscv-sr.cc: ...here.
* config/riscv/riscv.c: Moved to...
* config/riscv/riscv.cc: ...here.
* config/rl78/rl78-c.c: Moved to...
* config/rl78/rl78-c.cc: ...here.
* config/rl78/rl78.c: Moved to...
* config/rl78/rl78.cc: ...here.
* config/rs6000/driver-rs6000.c: Moved to...
* config/rs6000/driver-rs6000.cc: ...here.
* config/rs6000/host-darwin.c: Moved to...
* config/rs6000/host-darwin.cc: ...here.
* config/rs6000/host-ppc64-darwin.c: Moved to...
* config/rs6000/host-ppc64-darwin.cc: ...here.
* config/rs6000/rbtree.c: Moved to...
* config/rs6000/rbtree.cc: ...here.
* config/rs6000/rs6000-c.c: Moved to...
* config/rs6000/rs6000-c.cc: ...here.
* config/rs6000/rs6000-call.c: Moved to...
* config/rs6000/rs6000-call.cc: ...here.
* config/rs6000/rs6000-d.c: Moved to...
* config/rs6000/rs6000-d.cc: ...here.
* config/rs6000/rs6000-gen-builtins.c: Moved to...
* config/rs6000/rs6000-gen-builtins.cc: ...here.
* config/rs6000/rs6000-linux.c: Moved to...
* config/rs6000/rs6000-linux.cc: ...here.
* config/rs6000/rs6000-logue.c: Moved to...
* config/rs6000/rs6000-logue.cc: ...here.
* config/rs6000/rs6000-p8swap.c: Moved to...
* config/rs6000/rs6000-p8swap.cc: ...here.
* config/rs6000/rs6000-pcrel-opt.c: Moved to...
* config/rs6000/rs6000-pcrel-opt.cc: ...here.
* config/rs6000/rs6000-string.c: Moved to...
* config/rs6000/rs6000-string.cc: ...here.
* config/rs6000/rs6000.c: Moved to...
* config/rs6000/rs6000.cc: ...here.
* config/rx/rx.c: Moved to...
* config/rx/rx.cc: ...here.
* config/s390/driver-native.c: Moved to...
* config/s390/driver-native.cc: ...here.
* config/s390/s390-c.c: Moved to...
* config/s390/s390-c.cc: ...here.
* config/s390/s390-d.c: Moved to...
* config/s390/s390-d.cc: ...here.
* config/s390/s390.c: Moved to...
* config/s390/s390.cc: ...here.
* config/sh/divtab-sh4-300.c: Moved to...
* config/sh/divtab-sh4-300.cc: ...here.
* config/sh/divtab-sh4.c: Moved to...
* config/sh/divtab-sh4.cc: ...here.
* config/sh/divtab.c: Moved to...
* config/sh/divtab.cc: ...here.
* config/sh/sh-c.c: Moved to...
* config/sh/sh-c.cc: ...here.
* config/sh/sh.c: Moved to...
* config/sh/sh.cc: ...here.
* config/sol2-c.c: Moved to...
* config/sol2-c.cc: ...here.
* config/sol2-cxx.c: Moved to...
* config/sol2-cxx.cc: ...here.
* config/sol2-d.c: Moved to...
* config/sol2-d.cc: ...here.
* config/sol2-stubs.c: Moved to...
* config/sol2-stubs.cc: ...here.
* config/sol2.c: Moved to...
* config/sol2.cc: ...here.
* config/sparc/driver-sparc.c: Moved to...
* config/sparc/driver-sparc.cc: ...here.
* config/sparc/sparc-c.c: Moved to...
* config/sparc/sparc-c.cc: ...here.
* config/sparc/sparc-d.c: Moved to...
* config/sparc/sparc-d.cc: ...here.
* config/sparc/sparc.c: Moved to...
* config/sparc/sparc.cc: ...here.
* config/stormy16/stormy16.c: Moved to...
* config/stormy16/stormy16.cc: ...here.
* config/tilegx/mul-tables.c: Moved to...
* config/tilegx/mul-tables.cc: ...here.
* config/tilegx/tilegx-c.c: Moved to...
* config/tilegx/tilegx-c.cc: ...here.
* config/tilegx/tilegx.c: Moved to...
* config/tilegx/tilegx.cc: ...here.
* config/tilepro/mul-tables.c: Moved to...
* config/tilepro/mul-tables.cc: ...here.
* config/tilepro/tilepro-c.c: Moved to...
* config/tilepro/tilepro-c.cc: ...here.
* config/tilepro/tilepro.c: Moved to...
* config/tilepro/tilepro.cc: ...here.
* config/v850/v850-c.c: Moved to...
* config/v850/v850-c.cc: ...here.
* config/v850/v850.c: Moved to...
* config/v850/v850.cc: ...here.
* config/vax/vax.c: Moved to...
* config/vax/vax.cc: ...here.
* config/visium/visium.c: Moved to...
* config/visium/visium.cc: ...here.
* config/vms/vms-c.c: Moved to...
* config/vms/vms-c.cc: ...here.
* config/vms/vms-f.c: Moved to...
* config/vms/vms-f.cc: ...here.
* config/vms/vms.c: Moved to...
* config/vms/vms.cc: ...here.
* config/vxworks-c.c: Moved to...
* config/vxworks-c.cc: ...here.
* config/vxworks.c: Moved to...
* config/vxworks.cc: ...here.
* config/winnt-c.c: Moved to...
* config/winnt-c.cc: ...here.
* config/xtensa/xtensa.c: Moved to...
* config/xtensa/xtensa.cc: ...here.
* context.c: Moved to...
* context.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* coverage.c: Moved to...
* coverage.cc: ...here.
* cppbuiltin.c: Moved to...
* cppbuiltin.cc: ...here.
* cppdefault.c: Moved to...
* cppdefault.cc: ...here.
* cprop.c: Moved to...
* cprop.cc: ...here.
* cse.c: Moved to...
* cse.cc: ...here.
* cselib.c: Moved to...
* cselib.cc: ...here.
* ctfc.c: Moved to...
* ctfc.cc: ...here.
* ctfout.c: Moved to...
* ctfout.cc: ...here.
* data-streamer-in.c: Moved to...
* data-streamer-in.cc: ...here.
* data-streamer-out.c: Moved to...
* data-streamer-out.cc: ...here.
* data-streamer.c: Moved to...
* data-streamer.cc: ...here.
* dbgcnt.c: Moved to...
* dbgcnt.cc: ...here.
* dbxout.c: Moved to...
* dbxout.cc: ...here.
* dce.c: Moved to...
* dce.cc: ...here.
* ddg.c: Moved to...
* ddg.cc: ...here.
* debug.c: Moved to...
* debug.cc: ...here.
* df-core.c: Moved to...
* df-core.cc: ...here.
* df-problems.c: Moved to...
* df-problems.cc: ...here.
* df-scan.c: Moved to...
* df-scan.cc: ...here.
* dfp.c: Moved to...
* dfp.cc: ...here.
* diagnostic-color.c: Moved to...
* diagnostic-color.cc: ...here.
* diagnostic-show-locus.c: Moved to...
* diagnostic-show-locus.cc: ...here.
* diagnostic-spec.c: Moved to...
* diagnostic-spec.cc: ...here.
* diagnostic.c: Moved to...
* diagnostic.cc: ...here.
* dojump.c: Moved to...
* dojump.cc: ...here.
* dominance.c: Moved to...
* dominance.cc: ...here.
* domwalk.c: Moved to...
* domwalk.cc: ...here.
* double-int.c: Moved to...
* double-int.cc: ...here.
* dse.c: Moved to...
* dse.cc: ...here.
* dumpfile.c: Moved to...
* dumpfile.cc: ...here.
* dwarf2asm.c: Moved to...
* dwarf2asm.cc: ...here.
* dwarf2cfi.c: Moved to...
* dwarf2cfi.cc: ...here.
* dwarf2ctf.c: Moved to...
* dwarf2ctf.cc: ...here.
* dwarf2out.c: Moved to...
* dwarf2out.cc: ...here.
* early-remat.c: Moved to...
* early-remat.cc: ...here.
* edit-context.c: Moved to...
* edit-context.cc: ...here.
* emit-rtl.c: Moved to...
* emit-rtl.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* et-forest.c: Moved to...
* et-forest.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* explow.c: Moved to...
* explow.cc: ...here.
* expmed.c: Moved to...
* expmed.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* fibonacci_heap.c: Moved to...
* fibonacci_heap.cc: ...here.
* file-find.c: Moved to...
* file-find.cc: ...here.
* file-prefix-map.c: Moved to...
* file-prefix-map.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* fixed-value.c: Moved to...
* fixed-value.cc: ...here.
* fold-const-call.c: Moved to...
* fold-const-call.cc: ...here.
* fold-const.c: Moved to...
* fold-const.cc: ...here.
* fp-test.c: Moved to...
* fp-test.cc: ...here.
* function-tests.c: Moved to...
* function-tests.cc: ...here.
* function.c: Moved to...
* function.cc: ...here.
* fwprop.c: Moved to...
* fwprop.cc: ...here.
* gcc-ar.c: Moved to...
* gcc-ar.cc: ...here.
* gcc-main.c: Moved to...
* gcc-main.cc: ...here.
* gcc-rich-location.c: Moved to...
* gcc-rich-location.cc: ...here.
* gcc.c: Moved to...
* gcc.cc: ...here.
* gcov-dump.c: Moved to...
* gcov-dump.cc: ...here.
* gcov-io.c: Moved to...
* gcov-io.cc: ...here.
* gcov-tool.c: Moved to...
* gcov-tool.cc: ...here.
* gcov.c: Moved to...
* gcov.cc: ...here.
* gcse-common.c: Moved to...
* gcse-common.cc: ...here.
* gcse.c: Moved to...
* gcse.cc: ...here.
* genattr-common.c: Moved to...
* genattr-common.cc: ...here.
* genattr.c: Moved to...
* genattr.cc: ...here.
* genattrtab.c: Moved to...
* genattrtab.cc: ...here.
* genautomata.c: Moved to...
* genautomata.cc: ...here.
* gencfn-macros.c: Moved to...
* gencfn-macros.cc: ...here.
* gencheck.c: Moved to...
* gencheck.cc: ...here.
* genchecksum.c: Moved to...
* genchecksum.cc: ...here.
* gencodes.c: Moved to...
* gencodes.cc: ...here.
* genconditions.c: Moved to...
* genconditions.cc: ...here.
* genconfig.c: Moved to...
* genconfig.cc: ...here.
* genconstants.c: Moved to...
* genconstants.cc: ...here.
* genemit.c: Moved to...
* genemit.cc: ...here.
* genenums.c: Moved to...
* genenums.cc: ...here.
* generic-match-head.c: Moved to...
* generic-match-head.cc: ...here.
* genextract.c: Moved to...
* genextract.cc: ...here.
* genflags.c: Moved to...
* genflags.cc: ...here.
* gengenrtl.c: Moved to...
* gengenrtl.cc: ...here.
* gengtype-parse.c: Moved to...
* gengtype-parse.cc: ...here.
* gengtype-state.c: Moved to...
* gengtype-state.cc: ...here.
* gengtype.c: Moved to...
* gengtype.cc: ...here.
* genhooks.c: Moved to...
* genhooks.cc: ...here.
* genmatch.c: Moved to...
* genmatch.cc: ...here.
* genmddeps.c: Moved to...
* genmddeps.cc: ...here.
* genmddump.c: Moved to...
* genmddump.cc: ...here.
* genmodes.c: Moved to...
* genmodes.cc: ...here.
* genopinit.c: Moved to...
* genopinit.cc: ...here.
* genoutput.c: Moved to...
* genoutput.cc: ...here.
* genpeep.c: Moved to...
* genpeep.cc: ...here.
* genpreds.c: Moved to...
* genpreds.cc: ...here.
* genrecog.c: Moved to...
* genrecog.cc: ...here.
* gensupport.c: Moved to...
* gensupport.cc: ...here.
* gentarget-def.c: Moved to...
* gentarget-def.cc: ...here.
* genversion.c: Moved to...
* genversion.cc: ...here.
* ggc-common.c: Moved to...
* ggc-common.cc: ...here.
* ggc-none.c: Moved to...
* ggc-none.cc: ...here.
* ggc-page.c: Moved to...
* ggc-page.cc: ...here.
* ggc-tests.c: Moved to...
* ggc-tests.cc: ...here.
* gimple-builder.c: Moved to...
* gimple-builder.cc: ...here.
* gimple-expr.c: Moved to...
* gimple-expr.cc: ...here.
* gimple-fold.c: Moved to...
* gimple-fold.cc: ...here.
* gimple-iterator.c: Moved to...
* gimple-iterator.cc: ...here.
* gimple-laddress.c: Moved to...
* gimple-laddress.cc: ...here.
* gimple-loop-jam.c: Moved to...
* gimple-loop-jam.cc: ...here.
* gimple-low.c: Moved to...
* gimple-low.cc: ...here.
* gimple-match-head.c: Moved to...
* gimple-match-head.cc: ...here.
* gimple-pretty-print.c: Moved to...
* gimple-pretty-print.cc: ...here.
* gimple-ssa-backprop.c: Moved to...
* gimple-ssa-backprop.cc: ...here.
* gimple-ssa-evrp-analyze.c: Moved to...
* gimple-ssa-evrp-analyze.cc: ...here.
* gimple-ssa-evrp.c: Moved to...
* gimple-ssa-evrp.cc: ...here.
* gimple-ssa-isolate-paths.c: Moved to...
* gimple-ssa-isolate-paths.cc: ...here.
* gimple-ssa-nonnull-compare.c: Moved to...
* gimple-ssa-nonnull-compare.cc: ...here.
* gimple-ssa-split-paths.c: Moved to...
* gimple-ssa-split-paths.cc: ...here.
* gimple-ssa-sprintf.c: Moved to...
* gimple-ssa-sprintf.cc: ...here.
* gimple-ssa-store-merging.c: Moved to...
* gimple-ssa-store-merging.cc: ...here.
* gimple-ssa-strength-reduction.c: Moved to...
* gimple-ssa-strength-reduction.cc: ...here.
* gimple-ssa-warn-alloca.c: Moved to...
* gimple-ssa-warn-alloca.cc: ...here.
* gimple-ssa-warn-restrict.c: Moved to...
* gimple-ssa-warn-restrict.cc: ...here.
* gimple-streamer-in.c: Moved to...
* gimple-streamer-in.cc: ...here.
* gimple-streamer-out.c: Moved to...
* gimple-streamer-out.cc: ...here.
* gimple-walk.c: Moved to...
* gimple-walk.cc: ...here.
* gimple-warn-recursion.c: Moved to...
* gimple-warn-recursion.cc: ...here.
* gimple.c: Moved to...
* gimple.cc: ...here.
* gimplify-me.c: Moved to...
* gimplify-me.cc: ...here.
* gimplify.c: Moved to...
* gimplify.cc: ...here.
* godump.c: Moved to...
* godump.cc: ...here.
* graph.c: Moved to...
* graph.cc: ...here.
* graphds.c: Moved to...
* graphds.cc: ...here.
* graphite-dependences.c: Moved to...
* graphite-dependences.cc: ...here.
* graphite-isl-ast-to-gimple.c: Moved to...
* graphite-isl-ast-to-gimple.cc: ...here.
* graphite-optimize-isl.c: Moved to...
* graphite-optimize-isl.cc: ...here.
* graphite-poly.c: Moved to...
* graphite-poly.cc: ...here.
* graphite-scop-detection.c: Moved to...
* graphite-scop-detection.cc: ...here.
* graphite-sese-to-poly.c: Moved to...
* graphite-sese-to-poly.cc: ...here.
* graphite.c: Moved to...
* graphite.cc: ...here.
* haifa-sched.c: Moved to...
* haifa-sched.cc: ...here.
* hash-map-tests.c: Moved to...
* hash-map-tests.cc: ...here.
* hash-set-tests.c: Moved to...
* hash-set-tests.cc: ...here.
* hash-table.c: Moved to...
* hash-table.cc: ...here.
* hooks.c: Moved to...
* hooks.cc: ...here.
* host-default.c: Moved to...
* host-default.cc: ...here.
* hw-doloop.c: Moved to...
* hw-doloop.cc: ...here.
* hwint.c: Moved to...
* hwint.cc: ...here.
* ifcvt.c: Moved to...
* ifcvt.cc: ...here.
* inchash.c: Moved to...
* inchash.cc: ...here.
* incpath.c: Moved to...
* incpath.cc: ...here.
* init-regs.c: Moved to...
* init-regs.cc: ...here.
* input.c: Moved to...
* input.cc: ...here.
* internal-fn.c: Moved to...
* internal-fn.cc: ...here.
* intl.c: Moved to...
* intl.cc: ...here.
* ipa-comdats.c: Moved to...
* ipa-comdats.cc: ...here.
* ipa-cp.c: Moved to...
* ipa-cp.cc: ...here.
* ipa-devirt.c: Moved to...
* ipa-devirt.cc: ...here.
* ipa-fnsummary.c: Moved to...
* ipa-fnsummary.cc: ...here.
* ipa-icf-gimple.c: Moved to...
* ipa-icf-gimple.cc: ...here.
* ipa-icf.c: Moved to...
* ipa-icf.cc: ...here.
* ipa-inline-analysis.c: Moved to...
* ipa-inline-analysis.cc: ...here.
* ipa-inline-transform.c: Moved to...
* ipa-inline-transform.cc: ...here.
* ipa-inline.c: Moved to...
* ipa-inline.cc: ...here.
* ipa-modref-tree.c: Moved to...
* ipa-modref-tree.cc: ...here.
* ipa-modref.c: Moved to...
* ipa-modref.cc: ...here.
* ipa-param-manipulation.c: Moved to...
* ipa-param-manipulation.cc: ...here.
* ipa-polymorphic-call.c: Moved to...
* ipa-polymorphic-call.cc: ...here.
* ipa-predicate.c: Moved to...
* ipa-predicate.cc: ...here.
* ipa-profile.c: Moved to...
* ipa-profile.cc: ...here.
* ipa-prop.c: Moved to...
* ipa-prop.cc: ...here.
* ipa-pure-const.c: Moved to...
* ipa-pure-const.cc: ...here.
* ipa-ref.c: Moved to...
* ipa-ref.cc: ...here.
* ipa-reference.c: Moved to...
* ipa-reference.cc: ...here.
* ipa-split.c: Moved to...
* ipa-split.cc: ...here.
* ipa-sra.c: Moved to...
* ipa-sra.cc: ...here.
* ipa-utils.c: Moved to...
* ipa-utils.cc: ...here.
* ipa-visibility.c: Moved to...
* ipa-visibility.cc: ...here.
* ipa.c: Moved to...
* ipa.cc: ...here.
* ira-build.c: Moved to...
* ira-build.cc: ...here.
* ira-color.c: Moved to...
* ira-color.cc: ...here.
* ira-conflicts.c: Moved to...
* ira-conflicts.cc: ...here.
* ira-costs.c: Moved to...
* ira-costs.cc: ...here.
* ira-emit.c: Moved to...
* ira-emit.cc: ...here.
* ira-lives.c: Moved to...
* ira-lives.cc: ...here.
* ira.c: Moved to...
* ira.cc: ...here.
* jump.c: Moved to...
* jump.cc: ...here.
* langhooks.c: Moved to...
* langhooks.cc: ...here.
* lcm.c: Moved to...
* lcm.cc: ...here.
* lists.c: Moved to...
* lists.cc: ...here.
* loop-doloop.c: Moved to...
* loop-doloop.cc: ...here.
* loop-init.c: Moved to...
* loop-init.cc: ...here.
* loop-invariant.c: Moved to...
* loop-invariant.cc: ...here.
* loop-iv.c: Moved to...
* loop-iv.cc: ...here.
* loop-unroll.c: Moved to...
* loop-unroll.cc: ...here.
* lower-subreg.c: Moved to...
* lower-subreg.cc: ...here.
* lra-assigns.c: Moved to...
* lra-assigns.cc: ...here.
* lra-coalesce.c: Moved to...
* lra-coalesce.cc: ...here.
* lra-constraints.c: Moved to...
* lra-constraints.cc: ...here.
* lra-eliminations.c: Moved to...
* lra-eliminations.cc: ...here.
* lra-lives.c: Moved to...
* lra-lives.cc: ...here.
* lra-remat.c: Moved to...
* lra-remat.cc: ...here.
* lra-spills.c: Moved to...
* lra-spills.cc: ...here.
* lra.c: Moved to...
* lra.cc: ...here.
* lto-cgraph.c: Moved to...
* lto-cgraph.cc: ...here.
* lto-compress.c: Moved to...
* lto-compress.cc: ...here.
* lto-opts.c: Moved to...
* lto-opts.cc: ...here.
* lto-section-in.c: Moved to...
* lto-section-in.cc: ...here.
* lto-section-out.c: Moved to...
* lto-section-out.cc: ...here.
* lto-streamer-in.c: Moved to...
* lto-streamer-in.cc: ...here.
* lto-streamer-out.c: Moved to...
* lto-streamer-out.cc: ...here.
* lto-streamer.c: Moved to...
* lto-streamer.cc: ...here.
* lto-wrapper.c: Moved to...
* lto-wrapper.cc: ...here.
* main.c: Moved to...
* main.cc: ...here.
* mcf.c: Moved to...
* mcf.cc: ...here.
* mode-switching.c: Moved to...
* mode-switching.cc: ...here.
* modulo-sched.c: Moved to...
* modulo-sched.cc: ...here.
* multiple_target.c: Moved to...
* multiple_target.cc: ...here.
* omp-expand.c: Moved to...
* omp-expand.cc: ...here.
* omp-general.c: Moved to...
* omp-general.cc: ...here.
* omp-low.c: Moved to...
* omp-low.cc: ...here.
* omp-offload.c: Moved to...
* omp-offload.cc: ...here.
* omp-simd-clone.c: Moved to...
* omp-simd-clone.cc: ...here.
* opt-suggestions.c: Moved to...
* opt-suggestions.cc: ...here.
* optabs-libfuncs.c: Moved to...
* optabs-libfuncs.cc: ...here.
* optabs-query.c: Moved to...
* optabs-query.cc: ...here.
* optabs-tree.c: Moved to...
* optabs-tree.cc: ...here.
* optabs.c: Moved to...
* optabs.cc: ...here.
* opts-common.c: Moved to...
* opts-common.cc: ...here.
* opts-global.c: Moved to...
* opts-global.cc: ...here.
* opts.c: Moved to...
* opts.cc: ...here.
* passes.c: Moved to...
* passes.cc: ...here.
* plugin.c: Moved to...
* plugin.cc: ...here.
* postreload-gcse.c: Moved to...
* postreload-gcse.cc: ...here.
* postreload.c: Moved to...
* postreload.cc: ...here.
* predict.c: Moved to...
* predict.cc: ...here.
* prefix.c: Moved to...
* prefix.cc: ...here.
* pretty-print.c: Moved to...
* pretty-print.cc: ...here.
* print-rtl-function.c: Moved to...
* print-rtl-function.cc: ...here.
* print-rtl.c: Moved to...
* print-rtl.cc: ...here.
* print-tree.c: Moved to...
* print-tree.cc: ...here.
* profile-count.c: Moved to...
* profile-count.cc: ...here.
* profile.c: Moved to...
* profile.cc: ...here.
* read-md.c: Moved to...
* read-md.cc: ...here.
* read-rtl-function.c: Moved to...
* read-rtl-function.cc: ...here.
* read-rtl.c: Moved to...
* read-rtl.cc: ...here.
* real.c: Moved to...
* real.cc: ...here.
* realmpfr.c: Moved to...
* realmpfr.cc: ...here.
* recog.c: Moved to...
* recog.cc: ...here.
* ree.c: Moved to...
* ree.cc: ...here.
* reg-stack.c: Moved to...
* reg-stack.cc: ...here.
* regcprop.c: Moved to...
* regcprop.cc: ...here.
* reginfo.c: Moved to...
* reginfo.cc: ...here.
* regrename.c: Moved to...
* regrename.cc: ...here.
* regstat.c: Moved to...
* regstat.cc: ...here.
* reload.c: Moved to...
* reload.cc: ...here.
* reload1.c: Moved to...
* reload1.cc: ...here.
* reorg.c: Moved to...
* reorg.cc: ...here.
* resource.c: Moved to...
* resource.cc: ...here.
* rtl-error.c: Moved to...
* rtl-error.cc: ...here.
* rtl-tests.c: Moved to...
* rtl-tests.cc: ...here.
* rtl.c: Moved to...
* rtl.cc: ...here.
* rtlanal.c: Moved to...
* rtlanal.cc: ...here.
* rtlhash.c: Moved to...
* rtlhash.cc: ...here.
* rtlhooks.c: Moved to...
* rtlhooks.cc: ...here.
* rtx-vector-builder.c: Moved to...
* rtx-vector-builder.cc: ...here.
* run-rtl-passes.c: Moved to...
* run-rtl-passes.cc: ...here.
* sancov.c: Moved to...
* sancov.cc: ...here.
* sanopt.c: Moved to...
* sanopt.cc: ...here.
* sbitmap.c: Moved to...
* sbitmap.cc: ...here.
* sched-deps.c: Moved to...
* sched-deps.cc: ...here.
* sched-ebb.c: Moved to...
* sched-ebb.cc: ...here.
* sched-rgn.c: Moved to...
* sched-rgn.cc: ...here.
* sel-sched-dump.c: Moved to...
* sel-sched-dump.cc: ...here.
* sel-sched-ir.c: Moved to...
* sel-sched-ir.cc: ...here.
* sel-sched.c: Moved to...
* sel-sched.cc: ...here.
* selftest-diagnostic.c: Moved to...
* selftest-diagnostic.cc: ...here.
* selftest-rtl.c: Moved to...
* selftest-rtl.cc: ...here.
* selftest-run-tests.c: Moved to...
* selftest-run-tests.cc: ...here.
* selftest.c: Moved to...
* selftest.cc: ...here.
* sese.c: Moved to...
* sese.cc: ...here.
* shrink-wrap.c: Moved to...
* shrink-wrap.cc: ...here.
* simplify-rtx.c: Moved to...
* simplify-rtx.cc: ...here.
* sparseset.c: Moved to...
* sparseset.cc: ...here.
* spellcheck-tree.c: Moved to...
* spellcheck-tree.cc: ...here.
* spellcheck.c: Moved to...
* spellcheck.cc: ...here.
* sreal.c: Moved to...
* sreal.cc: ...here.
* stack-ptr-mod.c: Moved to...
* stack-ptr-mod.cc: ...here.
* statistics.c: Moved to...
* statistics.cc: ...here.
* stmt.c: Moved to...
* stmt.cc: ...here.
* stor-layout.c: Moved to...
* stor-layout.cc: ...here.
* store-motion.c: Moved to...
* store-motion.cc: ...here.
* streamer-hooks.c: Moved to...
* streamer-hooks.cc: ...here.
* stringpool.c: Moved to...
* stringpool.cc: ...here.
* substring-locations.c: Moved to...
* substring-locations.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* target-globals.c: Moved to...
* target-globals.cc: ...here.
* targhooks.c: Moved to...
* targhooks.cc: ...here.
* timevar.c: Moved to...
* timevar.cc: ...here.
* toplev.c: Moved to...
* toplev.cc: ...here.
* tracer.c: Moved to...
* tracer.cc: ...here.
* trans-mem.c: Moved to...
* trans-mem.cc: ...here.
* tree-affine.c: Moved to...
* tree-affine.cc: ...here.
* tree-call-cdce.c: Moved to...
* tree-call-cdce.cc: ...here.
* tree-cfg.c: Moved to...
* tree-cfg.cc: ...here.
* tree-cfgcleanup.c: Moved to...
* tree-cfgcleanup.cc: ...here.
* tree-chrec.c: Moved to...
* tree-chrec.cc: ...here.
* tree-complex.c: Moved to...
* tree-complex.cc: ...here.
* tree-data-ref.c: Moved to...
* tree-data-ref.cc: ...here.
* tree-dfa.c: Moved to...
* tree-dfa.cc: ...here.
* tree-diagnostic.c: Moved to...
* tree-diagnostic.cc: ...here.
* tree-dump.c: Moved to...
* tree-dump.cc: ...here.
* tree-eh.c: Moved to...
* tree-eh.cc: ...here.
* tree-emutls.c: Moved to...
* tree-emutls.cc: ...here.
* tree-if-conv.c: Moved to...
* tree-if-conv.cc: ...here.
* tree-inline.c: Moved to...
* tree-inline.cc: ...here.
* tree-into-ssa.c: Moved to...
* tree-into-ssa.cc: ...here.
* tree-iterator.c: Moved to...
* tree-iterator.cc: ...here.
* tree-loop-distribution.c: Moved to...
* tree-loop-distribution.cc: ...here.
* tree-nested.c: Moved to...
* tree-nested.cc: ...here.
* tree-nrv.c: Moved to...
* tree-nrv.cc: ...here.
* tree-object-size.c: Moved to...
* tree-object-size.cc: ...here.
* tree-outof-ssa.c: Moved to...
* tree-outof-ssa.cc: ...here.
* tree-parloops.c: Moved to...
* tree-parloops.cc: ...here.
* tree-phinodes.c: Moved to...
* tree-phinodes.cc: ...here.
* tree-predcom.c: Moved to...
* tree-predcom.cc: ...here.
* tree-pretty-print.c: Moved to...
* tree-pretty-print.cc: ...here.
* tree-profile.c: Moved to...
* tree-profile.cc: ...here.
* tree-scalar-evolution.c: Moved to...
* tree-scalar-evolution.cc: ...here.
* tree-sra.c: Moved to...
* tree-sra.cc: ...here.
* tree-ssa-address.c: Moved to...
* tree-ssa-address.cc: ...here.
* tree-ssa-alias.c: Moved to...
* tree-ssa-alias.cc: ...here.
* tree-ssa-ccp.c: Moved to...
* tree-ssa-ccp.cc: ...here.
* tree-ssa-coalesce.c: Moved to...
* tree-ssa-coalesce.cc: ...here.
* tree-ssa-copy.c: Moved to...
* tree-ssa-copy.cc: ...here.
* tree-ssa-dce.c: Moved to...
* tree-ssa-dce.cc: ...here.
* tree-ssa-dom.c: Moved to...
* tree-ssa-dom.cc: ...here.
* tree-ssa-dse.c: Moved to...
* tree-ssa-dse.cc: ...here.
* tree-ssa-forwprop.c: Moved to...
* tree-ssa-forwprop.cc: ...here.
* tree-ssa-ifcombine.c: Moved to...
* tree-ssa-ifcombine.cc: ...here.
* tree-ssa-live.c: Moved to...
* tree-ssa-live.cc: ...here.
* tree-ssa-loop-ch.c: Moved to...
* tree-ssa-loop-ch.cc: ...here.
* tree-ssa-loop-im.c: Moved to...
* tree-ssa-loop-im.cc: ...here.
* tree-ssa-loop-ivcanon.c: Moved to...
* tree-ssa-loop-ivcanon.cc: ...here.
* tree-ssa-loop-ivopts.c: Moved to...
* tree-ssa-loop-ivopts.cc: ...here.
* tree-ssa-loop-manip.c: Moved to...
* tree-ssa-loop-manip.cc: ...here.
* tree-ssa-loop-niter.c: Moved to...
* tree-ssa-loop-niter.cc: ...here.
* tree-ssa-loop-prefetch.c: Moved to...
* tree-ssa-loop-prefetch.cc: ...here.
* tree-ssa-loop-split.c: Moved to...
* tree-ssa-loop-split.cc: ...here.
* tree-ssa-loop-unswitch.c: Moved to...
* tree-ssa-loop-unswitch.cc: ...here.
* tree-ssa-loop.c: Moved to...
* tree-ssa-loop.cc: ...here.
* tree-ssa-math-opts.c: Moved to...
* tree-ssa-math-opts.cc: ...here.
* tree-ssa-operands.c: Moved to...
* tree-ssa-operands.cc: ...here.
* tree-ssa-phiopt.c: Moved to...
* tree-ssa-phiopt.cc: ...here.
* tree-ssa-phiprop.c: Moved to...
* tree-ssa-phiprop.cc: ...here.
* tree-ssa-pre.c: Moved to...
* tree-ssa-pre.cc: ...here.
* tree-ssa-propagate.c: Moved to...
* tree-ssa-propagate.cc: ...here.
* tree-ssa-reassoc.c: Moved to...
* tree-ssa-reassoc.cc: ...here.
* tree-ssa-sccvn.c: Moved to...
* tree-ssa-sccvn.cc: ...here.
* tree-ssa-scopedtables.c: Moved to...
* tree-ssa-scopedtables.cc: ...here.
* tree-ssa-sink.c: Moved to...
* tree-ssa-sink.cc: ...here.
* tree-ssa-strlen.c: Moved to...
* tree-ssa-strlen.cc: ...here.
* tree-ssa-structalias.c: Moved to...
* tree-ssa-structalias.cc: ...here.
* tree-ssa-tail-merge.c: Moved to...
* tree-ssa-tail-merge.cc: ...here.
* tree-ssa-ter.c: Moved to...
* tree-ssa-ter.cc: ...here.
* tree-ssa-threadbackward.c: Moved to...
* tree-ssa-threadbackward.cc: ...here.
* tree-ssa-threadedge.c: Moved to...
* tree-ssa-threadedge.cc: ...here.
* tree-ssa-threadupdate.c: Moved to...
* tree-ssa-threadupdate.cc: ...here.
* tree-ssa-uncprop.c: Moved to...
* tree-ssa-uncprop.cc: ...here.
* tree-ssa-uninit.c: Moved to...
* tree-ssa-uninit.cc: ...here.
* tree-ssa.c: Moved to...
* tree-ssa.cc: ...here.
* tree-ssanames.c: Moved to...
* tree-ssanames.cc: ...here.
* tree-stdarg.c: Moved to...
* tree-stdarg.cc: ...here.
* tree-streamer-in.c: Moved to...
* tree-streamer-in.cc: ...here.
* tree-streamer-out.c: Moved to...
* tree-streamer-out.cc: ...here.
* tree-streamer.c: Moved to...
* tree-streamer.cc: ...here.
* tree-switch-conversion.c: Moved to...
* tree-switch-conversion.cc: ...here.
* tree-tailcall.c: Moved to...
* tree-tailcall.cc: ...here.
* tree-vect-data-refs.c: Moved to...
* tree-vect-data-refs.cc: ...here.
* tree-vect-generic.c: Moved to...
* tree-vect-generic.cc: ...here.
* tree-vect-loop-manip.c: Moved to...
* tree-vect-loop-manip.cc: ...here.
* tree-vect-loop.c: Moved to...
* tree-vect-loop.cc: ...here.
* tree-vect-patterns.c: Moved to...
* tree-vect-patterns.cc: ...here.
* tree-vect-slp-patterns.c: Moved to...
* tree-vect-slp-patterns.cc: ...here.
* tree-vect-slp.c: Moved to...
* tree-vect-slp.cc: ...here.
* tree-vect-stmts.c: Moved to...
* tree-vect-stmts.cc: ...here.
* tree-vector-builder.c: Moved to...
* tree-vector-builder.cc: ...here.
* tree-vectorizer.c: Moved to...
* tree-vectorizer.cc: ...here.
* tree-vrp.c: Moved to...
* tree-vrp.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* tsan.c: Moved to...
* tsan.cc: ...here.
* typed-splay-tree.c: Moved to...
* typed-splay-tree.cc: ...here.
* ubsan.c: Moved to...
* ubsan.cc: ...here.
* valtrack.c: Moved to...
* valtrack.cc: ...here.
* value-prof.c: Moved to...
* value-prof.cc: ...here.
* var-tracking.c: Moved to...
* var-tracking.cc: ...here.
* varasm.c: Moved to...
* varasm.cc: ...here.
* varpool.c: Moved to...
* varpool.cc: ...here.
* vec-perm-indices.c: Moved to...
* vec-perm-indices.cc: ...here.
* vec.c: Moved to...
* vec.cc: ...here.
* vmsdbgout.c: Moved to...
* vmsdbgout.cc: ...here.
* vr-values.c: Moved to...
* vr-values.cc: ...here.
* vtable-verify.c: Moved to...
* vtable-verify.cc: ...here.
* web.c: Moved to...
* web.cc: ...here.
* xcoffout.c: Moved to...
* xcoffout.cc: ...here.
gcc/c-family/ChangeLog:
* c-ada-spec.c: Moved to...
* c-ada-spec.cc: ...here.
* c-attribs.c: Moved to...
* c-attribs.cc: ...here.
* c-common.c: Moved to...
* c-common.cc: ...here.
* c-cppbuiltin.c: Moved to...
* c-cppbuiltin.cc: ...here.
* c-dump.c: Moved to...
* c-dump.cc: ...here.
* c-format.c: Moved to...
* c-format.cc: ...here.
* c-gimplify.c: Moved to...
* c-gimplify.cc: ...here.
* c-indentation.c: Moved to...
* c-indentation.cc: ...here.
* c-lex.c: Moved to...
* c-lex.cc: ...here.
* c-omp.c: Moved to...
* c-omp.cc: ...here.
* c-opts.c: Moved to...
* c-opts.cc: ...here.
* c-pch.c: Moved to...
* c-pch.cc: ...here.
* c-ppoutput.c: Moved to...
* c-ppoutput.cc: ...here.
* c-pragma.c: Moved to...
* c-pragma.cc: ...here.
* c-pretty-print.c: Moved to...
* c-pretty-print.cc: ...here.
* c-semantics.c: Moved to...
* c-semantics.cc: ...here.
* c-ubsan.c: Moved to...
* c-ubsan.cc: ...here.
* c-warn.c: Moved to...
* c-warn.cc: ...here.
* cppspec.c: Moved to...
* cppspec.cc: ...here.
* stub-objc.c: Moved to...
* stub-objc.cc: ...here.
gcc/c/ChangeLog:
* c-aux-info.c: Moved to...
* c-aux-info.cc: ...here.
* c-convert.c: Moved to...
* c-convert.cc: ...here.
* c-decl.c: Moved to...
* c-decl.cc: ...here.
* c-errors.c: Moved to...
* c-errors.cc: ...here.
* c-fold.c: Moved to...
* c-fold.cc: ...here.
* c-lang.c: Moved to...
* c-lang.cc: ...here.
* c-objc-common.c: Moved to...
* c-objc-common.cc: ...here.
* c-parser.c: Moved to...
* c-parser.cc: ...here.
* c-typeck.c: Moved to...
* c-typeck.cc: ...here.
* gccspec.c: Moved to...
* gccspec.cc: ...here.
* gimple-parser.c: Moved to...
* gimple-parser.cc: ...here.
gcc/cp/ChangeLog:
* call.c: Moved to...
* call.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constexpr.c: Moved to...
* constexpr.cc: ...here.
* cp-gimplify.c: Moved to...
* cp-gimplify.cc: ...here.
* cp-lang.c: Moved to...
* cp-lang.cc: ...here.
* cp-objcp-common.c: Moved to...
* cp-objcp-common.cc: ...here.
* cp-ubsan.c: Moved to...
* cp-ubsan.cc: ...here.
* cvt.c: Moved to...
* cvt.cc: ...here.
* cxx-pretty-print.c: Moved to...
* cxx-pretty-print.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* decl2.c: Moved to...
* decl2.cc: ...here.
* dump.c: Moved to...
* dump.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* friend.c: Moved to...
* friend.cc: ...here.
* g++spec.c: Moved to...
* g++spec.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lambda.c: Moved to...
* lambda.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* mangle.c: Moved to...
* mangle.cc: ...here.
* method.c: Moved to...
* method.cc: ...here.
* name-lookup.c: Moved to...
* name-lookup.cc: ...here.
* optimize.c: Moved to...
* optimize.cc: ...here.
* parser.c: Moved to...
* parser.cc: ...here.
* pt.c: Moved to...
* pt.cc: ...here.
* ptree.c: Moved to...
* ptree.cc: ...here.
* rtti.c: Moved to...
* rtti.cc: ...here.
* search.c: Moved to...
* search.cc: ...here.
* semantics.c: Moved to...
* semantics.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* typeck.c: Moved to...
* typeck.cc: ...here.
* typeck2.c: Moved to...
* typeck2.cc: ...here.
* vtable-class-hierarchy.c: Moved to...
* vtable-class-hierarchy.cc: ...here.
gcc/fortran/ChangeLog:
* arith.c: Moved to...
* arith.cc: ...here.
* array.c: Moved to...
* array.cc: ...here.
* bbt.c: Moved to...
* bbt.cc: ...here.
* check.c: Moved to...
* check.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constructor.c: Moved to...
* constructor.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* cpp.c: Moved to...
* cpp.cc: ...here.
* data.c: Moved to...
* data.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* dependency.c: Moved to...
* dependency.cc: ...here.
* dump-parse-tree.c: Moved to...
* dump-parse-tree.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* f95-lang.c: Moved to...
* f95-lang.cc: ...here.
* frontend-passes.c: Moved to...
* frontend-passes.cc: ...here.
* gfortranspec.c: Moved to...
* gfortranspec.cc: ...here.
* interface.c: Moved to...
* interface.cc: ...here.
* intrinsic.c: Moved to...
* intrinsic.cc: ...here.
* io.c: Moved to...
* io.cc: ...here.
* iresolve.c: Moved to...
* iresolve.cc: ...here.
* match.c: Moved to...
* match.cc: ...here.
* matchexp.c: Moved to...
* matchexp.cc: ...here.
* misc.c: Moved to...
* misc.cc: ...here.
* module.c: Moved to...
* module.cc: ...here.
* openmp.c: Moved to...
* openmp.cc: ...here.
* options.c: Moved to...
* options.cc: ...here.
* parse.c: Moved to...
* parse.cc: ...here.
* primary.c: Moved to...
* primary.cc: ...here.
* resolve.c: Moved to...
* resolve.cc: ...here.
* scanner.c: Moved to...
* scanner.cc: ...here.
* simplify.c: Moved to...
* simplify.cc: ...here.
* st.c: Moved to...
* st.cc: ...here.
* symbol.c: Moved to...
* symbol.cc: ...here.
* target-memory.c: Moved to...
* target-memory.cc: ...here.
* trans-array.c: Moved to...
* trans-array.cc: ...here.
* trans-common.c: Moved to...
* trans-common.cc: ...here.
* trans-const.c: Moved to...
* trans-const.cc: ...here.
* trans-decl.c: Moved to...
* trans-decl.cc: ...here.
* trans-expr.c: Moved to...
* trans-expr.cc: ...here.
* trans-intrinsic.c: Moved to...
* trans-intrinsic.cc: ...here.
* trans-io.c: Moved to...
* trans-io.cc: ...here.
* trans-openmp.c: Moved to...
* trans-openmp.cc: ...here.
* trans-stmt.c: Moved to...
* trans-stmt.cc: ...here.
* trans-types.c: Moved to...
* trans-types.cc: ...here.
* trans.c: Moved to...
* trans.cc: ...here.
gcc/go/ChangeLog:
* go-backend.c: Moved to...
* go-backend.cc: ...here.
* go-lang.c: Moved to...
* go-lang.cc: ...here.
* gospec.c: Moved to...
* gospec.cc: ...here.
gcc/jit/ChangeLog:
* dummy-frontend.c: Moved to...
* dummy-frontend.cc: ...here.
* jit-builtins.c: Moved to...
* jit-builtins.cc: ...here.
* jit-logging.c: Moved to...
* jit-logging.cc: ...here.
* jit-playback.c: Moved to...
* jit-playback.cc: ...here.
* jit-recording.c: Moved to...
* jit-recording.cc: ...here.
* jit-result.c: Moved to...
* jit-result.cc: ...here.
* jit-spec.c: Moved to...
* jit-spec.cc: ...here.
* jit-tempdir.c: Moved to...
* jit-tempdir.cc: ...here.
* jit-w32.c: Moved to...
* jit-w32.cc: ...here.
* libgccjit.c: Moved to...
* libgccjit.cc: ...here.
gcc/lto/ChangeLog:
* common.c: Moved to...
* common.cc: ...here.
* lto-common.c: Moved to...
* lto-common.cc: ...here.
* lto-dump.c: Moved to...
* lto-dump.cc: ...here.
* lto-lang.c: Moved to...
* lto-lang.cc: ...here.
* lto-object.c: Moved to...
* lto-object.cc: ...here.
* lto-partition.c: Moved to...
* lto-partition.cc: ...here.
* lto-symtab.c: Moved to...
* lto-symtab.cc: ...here.
* lto.c: Moved to...
* lto.cc: ...here.
gcc/objc/ChangeLog:
* objc-act.c: Moved to...
* objc-act.cc: ...here.
* objc-encoding.c: Moved to...
* objc-encoding.cc: ...here.
* objc-gnu-runtime-abi-01.c: Moved to...
* objc-gnu-runtime-abi-01.cc: ...here.
* objc-lang.c: Moved to...
* objc-lang.cc: ...here.
* objc-map.c: Moved to...
* objc-map.cc: ...here.
* objc-next-runtime-abi-01.c: Moved to...
* objc-next-runtime-abi-01.cc: ...here.
* objc-next-runtime-abi-02.c: Moved to...
* objc-next-runtime-abi-02.cc: ...here.
* objc-runtime-shared-support.c: Moved to...
* objc-runtime-shared-support.cc: ...here.
gcc/objcp/ChangeLog:
* objcp-decl.c: Moved to...
* objcp-decl.cc: ...here.
* objcp-lang.c: Moved to...
* objcp-lang.cc: ...here.
libcpp/ChangeLog:
* charset.c: Moved to...
* charset.cc: ...here.
* directives.c: Moved to...
* directives.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* files.c: Moved to...
* files.cc: ...here.
* identifiers.c: Moved to...
* identifiers.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* line-map.c: Moved to...
* line-map.cc: ...here.
* macro.c: Moved to...
* macro.cc: ...here.
* makeucnid.c: Moved to...
* makeucnid.cc: ...here.
* mkdeps.c: Moved to...
* mkdeps.cc: ...here.
* pch.c: Moved to...
* pch.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* traditional.c: Moved to...
* traditional.cc: ...here.
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 16582 |
1 files changed, 0 insertions, 16582 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c deleted file mode 100644 index d64d9c4..0000000 --- a/gcc/gimplify.c +++ /dev/null @@ -1,16582 +0,0 @@ -/* Tree lowering pass. This pass converts the GENERIC functions-as-trees - tree representation into the GIMPLE form. - Copyright (C) 2002-2022 Free Software Foundation, Inc. - Major work done by Sebastian Pop <s.pop@laposte.net>, - Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "target.h" -#include "rtl.h" -#include "tree.h" -#include "memmodel.h" -#include "tm_p.h" -#include "gimple.h" -#include "gimple-predict.h" -#include "tree-pass.h" /* FIXME: only for PROP_gimple_any */ -#include "ssa.h" -#include "cgraph.h" -#include "tree-pretty-print.h" -#include "diagnostic-core.h" -#include "alias.h" -#include "fold-const.h" -#include "calls.h" -#include "varasm.h" -#include "stmt.h" -#include "expr.h" -#include "gimple-fold.h" -#include "tree-eh.h" -#include "gimplify.h" -#include "gimple-iterator.h" -#include "stor-layout.h" -#include "print-tree.h" -#include "tree-iterator.h" -#include "tree-inline.h" -#include "langhooks.h" -#include "tree-cfg.h" -#include "tree-ssa.h" -#include "tree-hash-traits.h" -#include "omp-general.h" -#include "omp-low.h" -#include "gimple-low.h" -#include "gomp-constants.h" -#include "splay-tree.h" -#include "gimple-walk.h" -#include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */ -#include "builtins.h" -#include "stringpool.h" -#include "attribs.h" -#include "asan.h" -#include "dbgcnt.h" -#include "omp-offload.h" -#include "context.h" -#include "tree-nested.h" - -/* Hash set of poisoned variables in a bind expr. */ -static hash_set<tree> *asan_poisoned_variables = NULL; - -enum gimplify_omp_var_data -{ - GOVD_SEEN = 0x000001, - GOVD_EXPLICIT = 0x000002, - GOVD_SHARED = 0x000004, - GOVD_PRIVATE = 0x000008, - GOVD_FIRSTPRIVATE = 0x000010, - GOVD_LASTPRIVATE = 0x000020, - GOVD_REDUCTION = 0x000040, - GOVD_LOCAL = 0x00080, - GOVD_MAP = 0x000100, - GOVD_DEBUG_PRIVATE = 0x000200, - GOVD_PRIVATE_OUTER_REF = 0x000400, - GOVD_LINEAR = 0x000800, - GOVD_ALIGNED = 0x001000, - - /* Flag for GOVD_MAP: don't copy back. */ - GOVD_MAP_TO_ONLY = 0x002000, - - /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference. */ - GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 0x004000, - - GOVD_MAP_0LEN_ARRAY = 0x008000, - - /* Flag for GOVD_MAP, if it is always, to or always, tofrom mapping. */ - GOVD_MAP_ALWAYS_TO = 0x010000, - - /* Flag for shared vars that are or might be stored to in the region. */ - GOVD_WRITTEN = 0x020000, - - /* Flag for GOVD_MAP, if it is a forced mapping. */ - GOVD_MAP_FORCE = 0x040000, - - /* Flag for GOVD_MAP: must be present already. */ - GOVD_MAP_FORCE_PRESENT = 0x080000, - - /* Flag for GOVD_MAP: only allocate. */ - GOVD_MAP_ALLOC_ONLY = 0x100000, - - /* Flag for GOVD_MAP: only copy back. */ - GOVD_MAP_FROM_ONLY = 0x200000, - - GOVD_NONTEMPORAL = 0x400000, - - /* Flag for GOVD_LASTPRIVATE: conditional modifier. */ - GOVD_LASTPRIVATE_CONDITIONAL = 0x800000, - - GOVD_CONDTEMP = 0x1000000, - - /* Flag for GOVD_REDUCTION: inscan seen in {in,ex}clusive clause. */ - GOVD_REDUCTION_INSCAN = 0x2000000, - - /* Flag for GOVD_MAP: (struct) vars that have pointer attachments for - fields. */ - GOVD_MAP_HAS_ATTACHMENTS = 0x4000000, - - /* Flag for GOVD_FIRSTPRIVATE: OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT. */ - GOVD_FIRSTPRIVATE_IMPLICIT = 0x8000000, - - GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE - | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR - | GOVD_LOCAL) -}; - - -enum omp_region_type -{ - ORT_WORKSHARE = 0x00, - ORT_TASKGROUP = 0x01, - ORT_SIMD = 0x04, - - ORT_PARALLEL = 0x08, - ORT_COMBINED_PARALLEL = ORT_PARALLEL | 1, - - ORT_TASK = 0x10, - ORT_UNTIED_TASK = ORT_TASK | 1, - ORT_TASKLOOP = ORT_TASK | 2, - ORT_UNTIED_TASKLOOP = ORT_UNTIED_TASK | 2, - - ORT_TEAMS = 0x20, - ORT_COMBINED_TEAMS = ORT_TEAMS | 1, - ORT_HOST_TEAMS = ORT_TEAMS | 2, - ORT_COMBINED_HOST_TEAMS = ORT_COMBINED_TEAMS | 2, - - /* Data region. */ - ORT_TARGET_DATA = 0x40, - - /* Data region with offloading. */ - ORT_TARGET = 0x80, - ORT_COMBINED_TARGET = ORT_TARGET | 1, - ORT_IMPLICIT_TARGET = ORT_TARGET | 2, - - /* OpenACC variants. */ - ORT_ACC = 0x100, /* A generic OpenACC region. */ - ORT_ACC_DATA = ORT_ACC | ORT_TARGET_DATA, /* Data construct. */ - ORT_ACC_PARALLEL = ORT_ACC | ORT_TARGET, /* Parallel construct */ - ORT_ACC_KERNELS = ORT_ACC | ORT_TARGET | 2, /* Kernels construct. */ - ORT_ACC_SERIAL = ORT_ACC | ORT_TARGET | 4, /* Serial construct. */ - ORT_ACC_HOST_DATA = ORT_ACC | ORT_TARGET_DATA | 2, /* Host data. */ - - /* Dummy OpenMP region, used to disable expansion of - DECL_VALUE_EXPRs in taskloop pre body. */ - ORT_NONE = 0x200 -}; - -/* Gimplify hashtable helper. */ - -struct gimplify_hasher : free_ptr_hash <elt_t> -{ - static inline hashval_t hash (const elt_t *); - static inline bool equal (const elt_t *, const elt_t *); -}; - -struct gimplify_ctx -{ - struct gimplify_ctx *prev_context; - - vec<gbind *> bind_expr_stack; - tree temps; - gimple_seq conditional_cleanups; - tree exit_label; - tree return_temp; - - vec<tree> case_labels; - hash_set<tree> *live_switch_vars; - /* The formal temporary table. Should this be persistent? */ - hash_table<gimplify_hasher> *temp_htab; - - int conditions; - unsigned into_ssa : 1; - unsigned allow_rhs_cond_expr : 1; - unsigned in_cleanup_point_expr : 1; - unsigned keep_stack : 1; - unsigned save_stack : 1; - unsigned in_switch_expr : 1; -}; - -enum gimplify_defaultmap_kind -{ - GDMK_SCALAR, - GDMK_SCALAR_TARGET, /* w/ Fortran's target attr, implicit mapping, only. */ - GDMK_AGGREGATE, - GDMK_ALLOCATABLE, - GDMK_POINTER -}; - -struct gimplify_omp_ctx -{ - struct gimplify_omp_ctx *outer_context; - splay_tree variables; - hash_set<tree> *privatized_types; - tree clauses; - /* Iteration variables in an OMP_FOR. */ - vec<tree> loop_iter_var; - location_t location; - enum omp_clause_default_kind default_kind; - enum omp_region_type region_type; - enum tree_code code; - bool combined_loop; - bool distribute; - bool target_firstprivatize_array_bases; - bool add_safelen1; - bool order_concurrent; - bool has_depend; - bool in_for_exprs; - int defaultmap[5]; -}; - -static struct gimplify_ctx *gimplify_ctxp; -static struct gimplify_omp_ctx *gimplify_omp_ctxp; -static bool in_omp_construct; - -/* Forward declaration. */ -static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool); -static hash_map<tree, tree> *oacc_declare_returns; -static enum gimplify_status gimplify_expr (tree *, gimple_seq *, gimple_seq *, - bool (*) (tree), fallback_t, bool); - -/* Shorter alias name for the above function for use in gimplify.c - only. */ - -static inline void -gimplify_seq_add_stmt (gimple_seq *seq_p, gimple *gs) -{ - gimple_seq_add_stmt_without_update (seq_p, gs); -} - -/* Append sequence SRC to the end of sequence *DST_P. If *DST_P is - NULL, a new sequence is allocated. This function is - similar to gimple_seq_add_seq, but does not scan the operands. - During gimplification, we need to manipulate statement sequences - before the def/use vectors have been constructed. */ - -static void -gimplify_seq_add_seq (gimple_seq *dst_p, gimple_seq src) -{ - gimple_stmt_iterator si; - - if (src == NULL) - return; - - si = gsi_last (*dst_p); - gsi_insert_seq_after_without_update (&si, src, GSI_NEW_STMT); -} - - -/* Pointer to a list of allocated gimplify_ctx structs to be used for pushing - and popping gimplify contexts. */ - -static struct gimplify_ctx *ctx_pool = NULL; - -/* Return a gimplify context struct from the pool. */ - -static inline struct gimplify_ctx * -ctx_alloc (void) -{ - struct gimplify_ctx * c = ctx_pool; - - if (c) - ctx_pool = c->prev_context; - else - c = XNEW (struct gimplify_ctx); - - memset (c, '\0', sizeof (*c)); - return c; -} - -/* Put gimplify context C back into the pool. */ - -static inline void -ctx_free (struct gimplify_ctx *c) -{ - c->prev_context = ctx_pool; - ctx_pool = c; -} - -/* Free allocated ctx stack memory. */ - -void -free_gimplify_stack (void) -{ - struct gimplify_ctx *c; - - while ((c = ctx_pool)) - { - ctx_pool = c->prev_context; - free (c); - } -} - - -/* Set up a context for the gimplifier. */ - -void -push_gimplify_context (bool in_ssa, bool rhs_cond_ok) -{ - struct gimplify_ctx *c = ctx_alloc (); - - c->prev_context = gimplify_ctxp; - gimplify_ctxp = c; - gimplify_ctxp->into_ssa = in_ssa; - gimplify_ctxp->allow_rhs_cond_expr = rhs_cond_ok; -} - -/* Tear down a context for the gimplifier. If BODY is non-null, then - put the temporaries into the outer BIND_EXPR. Otherwise, put them - in the local_decls. - - BODY is not a sequence, but the first tuple in a sequence. */ - -void -pop_gimplify_context (gimple *body) -{ - struct gimplify_ctx *c = gimplify_ctxp; - - gcc_assert (c - && (!c->bind_expr_stack.exists () - || c->bind_expr_stack.is_empty ())); - c->bind_expr_stack.release (); - gimplify_ctxp = c->prev_context; - - if (body) - declare_vars (c->temps, body, false); - else - record_vars (c->temps); - - delete c->temp_htab; - c->temp_htab = NULL; - ctx_free (c); -} - -/* Push a GIMPLE_BIND tuple onto the stack of bindings. */ - -static void -gimple_push_bind_expr (gbind *bind_stmt) -{ - gimplify_ctxp->bind_expr_stack.reserve (8); - gimplify_ctxp->bind_expr_stack.safe_push (bind_stmt); -} - -/* Pop the first element off the stack of bindings. */ - -static void -gimple_pop_bind_expr (void) -{ - gimplify_ctxp->bind_expr_stack.pop (); -} - -/* Return the first element of the stack of bindings. */ - -gbind * -gimple_current_bind_expr (void) -{ - return gimplify_ctxp->bind_expr_stack.last (); -} - -/* Return the stack of bindings created during gimplification. */ - -vec<gbind *> -gimple_bind_expr_stack (void) -{ - return gimplify_ctxp->bind_expr_stack; -} - -/* Return true iff there is a COND_EXPR between us and the innermost - CLEANUP_POINT_EXPR. This info is used by gimple_push_cleanup. */ - -static bool -gimple_conditional_context (void) -{ - return gimplify_ctxp->conditions > 0; -} - -/* Note that we've entered a COND_EXPR. */ - -static void -gimple_push_condition (void) -{ -#ifdef ENABLE_GIMPLE_CHECKING - if (gimplify_ctxp->conditions == 0) - gcc_assert (gimple_seq_empty_p (gimplify_ctxp->conditional_cleanups)); -#endif - ++(gimplify_ctxp->conditions); -} - -/* Note that we've left a COND_EXPR. If we're back at unconditional scope - now, add any conditional cleanups we've seen to the prequeue. */ - -static void -gimple_pop_condition (gimple_seq *pre_p) -{ - int conds = --(gimplify_ctxp->conditions); - - gcc_assert (conds >= 0); - if (conds == 0) - { - gimplify_seq_add_seq (pre_p, gimplify_ctxp->conditional_cleanups); - gimplify_ctxp->conditional_cleanups = NULL; - } -} - -/* A stable comparison routine for use with splay trees and DECLs. */ - -static int -splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb) -{ - tree a = (tree) xa; - tree b = (tree) xb; - - return DECL_UID (a) - DECL_UID (b); -} - -/* Create a new omp construct that deals with variable remapping. */ - -static struct gimplify_omp_ctx * -new_omp_context (enum omp_region_type region_type) -{ - struct gimplify_omp_ctx *c; - - c = XCNEW (struct gimplify_omp_ctx); - c->outer_context = gimplify_omp_ctxp; - c->variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0); - c->privatized_types = new hash_set<tree>; - c->location = input_location; - c->region_type = region_type; - if ((region_type & ORT_TASK) == 0) - c->default_kind = OMP_CLAUSE_DEFAULT_SHARED; - else - c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; - c->defaultmap[GDMK_SCALAR] = GOVD_MAP; - c->defaultmap[GDMK_SCALAR_TARGET] = GOVD_MAP; - c->defaultmap[GDMK_AGGREGATE] = GOVD_MAP; - c->defaultmap[GDMK_ALLOCATABLE] = GOVD_MAP; - c->defaultmap[GDMK_POINTER] = GOVD_MAP; - - return c; -} - -/* Destroy an omp construct that deals with variable remapping. */ - -static void -delete_omp_context (struct gimplify_omp_ctx *c) -{ - splay_tree_delete (c->variables); - delete c->privatized_types; - c->loop_iter_var.release (); - XDELETE (c); -} - -static void omp_add_variable (struct gimplify_omp_ctx *, tree, unsigned int); -static bool omp_notice_variable (struct gimplify_omp_ctx *, tree, bool); - -/* Both gimplify the statement T and append it to *SEQ_P. This function - behaves exactly as gimplify_stmt, but you don't have to pass T as a - reference. */ - -void -gimplify_and_add (tree t, gimple_seq *seq_p) -{ - gimplify_stmt (&t, seq_p); -} - -/* Gimplify statement T into sequence *SEQ_P, and return the first - tuple in the sequence of generated tuples for this statement. - Return NULL if gimplifying T produced no tuples. */ - -static gimple * -gimplify_and_return_first (tree t, gimple_seq *seq_p) -{ - gimple_stmt_iterator last = gsi_last (*seq_p); - - gimplify_and_add (t, seq_p); - - if (!gsi_end_p (last)) - { - gsi_next (&last); - return gsi_stmt (last); - } - else - return gimple_seq_first_stmt (*seq_p); -} - -/* Returns true iff T is a valid RHS for an assignment to an un-renamed - LHS, or for a call argument. */ - -static bool -is_gimple_mem_rhs (tree t) -{ - /* If we're dealing with a renamable type, either source or dest must be - a renamed variable. */ - if (is_gimple_reg_type (TREE_TYPE (t))) - return is_gimple_val (t); - else - return is_gimple_val (t) || is_gimple_lvalue (t); -} - -/* Return true if T is a CALL_EXPR or an expression that can be - assigned to a temporary. Note that this predicate should only be - used during gimplification. See the rationale for this in - gimplify_modify_expr. */ - -static bool -is_gimple_reg_rhs_or_call (tree t) -{ - return (get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS - || TREE_CODE (t) == CALL_EXPR); -} - -/* Return true if T is a valid memory RHS or a CALL_EXPR. Note that - this predicate should only be used during gimplification. See the - rationale for this in gimplify_modify_expr. */ - -static bool -is_gimple_mem_rhs_or_call (tree t) -{ - /* If we're dealing with a renamable type, either source or dest must be - a renamed variable. */ - if (is_gimple_reg_type (TREE_TYPE (t))) - return is_gimple_val (t); - else - return (is_gimple_val (t) - || is_gimple_lvalue (t) - || TREE_CLOBBER_P (t) - || TREE_CODE (t) == CALL_EXPR); -} - -/* Create a temporary with a name derived from VAL. Subroutine of - lookup_tmp_var; nobody else should call this function. */ - -static inline tree -create_tmp_from_val (tree val) -{ - /* Drop all qualifiers and address-space information from the value type. */ - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (val)); - tree var = create_tmp_var (type, get_name (val)); - return var; -} - -/* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse - an existing expression temporary. */ - -static tree -lookup_tmp_var (tree val, bool is_formal) -{ - tree ret; - - /* If not optimizing, never really reuse a temporary. local-alloc - won't allocate any variable that is used in more than one basic - block, which means it will go into memory, causing much extra - work in reload and final and poorer code generation, outweighing - the extra memory allocation here. */ - if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val)) - ret = create_tmp_from_val (val); - else - { - elt_t elt, *elt_p; - elt_t **slot; - - elt.val = val; - if (!gimplify_ctxp->temp_htab) - gimplify_ctxp->temp_htab = new hash_table<gimplify_hasher> (1000); - slot = gimplify_ctxp->temp_htab->find_slot (&elt, INSERT); - if (*slot == NULL) - { - elt_p = XNEW (elt_t); - elt_p->val = val; - elt_p->temp = ret = create_tmp_from_val (val); - *slot = elt_p; - } - else - { - elt_p = *slot; - ret = elt_p->temp; - } - } - - return ret; -} - -/* Helper for get_formal_tmp_var and get_initialized_tmp_var. */ - -static tree -internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, - bool is_formal, bool allow_ssa) -{ - tree t, mod; - - /* Notice that we explicitly allow VAL to be a CALL_EXPR so that we - can create an INIT_EXPR and convert it into a GIMPLE_CALL below. */ - gimplify_expr (&val, pre_p, post_p, is_gimple_reg_rhs_or_call, - fb_rvalue); - - if (allow_ssa - && gimplify_ctxp->into_ssa - && is_gimple_reg_type (TREE_TYPE (val))) - { - t = make_ssa_name (TYPE_MAIN_VARIANT (TREE_TYPE (val))); - if (! gimple_in_ssa_p (cfun)) - { - const char *name = get_name (val); - if (name) - SET_SSA_NAME_VAR_OR_IDENTIFIER (t, create_tmp_var_name (name)); - } - } - else - t = lookup_tmp_var (val, is_formal); - - mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val)); - - SET_EXPR_LOCATION (mod, EXPR_LOC_OR_LOC (val, input_location)); - - /* gimplify_modify_expr might want to reduce this further. */ - gimplify_and_add (mod, pre_p); - ggc_free (mod); - - return t; -} - -/* Return a formal temporary variable initialized with VAL. PRE_P is as - in gimplify_expr. Only use this function if: - - 1) The value of the unfactored expression represented by VAL will not - change between the initialization and use of the temporary, and - 2) The temporary will not be otherwise modified. - - For instance, #1 means that this is inappropriate for SAVE_EXPR temps, - and #2 means it is inappropriate for && temps. - - For other cases, use get_initialized_tmp_var instead. */ - -tree -get_formal_tmp_var (tree val, gimple_seq *pre_p) -{ - return internal_get_tmp_var (val, pre_p, NULL, true, true); -} - -/* Return a temporary variable initialized with VAL. PRE_P and POST_P - are as in gimplify_expr. */ - -tree -get_initialized_tmp_var (tree val, gimple_seq *pre_p, - gimple_seq *post_p /* = NULL */, - bool allow_ssa /* = true */) -{ - return internal_get_tmp_var (val, pre_p, post_p, false, allow_ssa); -} - -/* Declare all the variables in VARS in SCOPE. If DEBUG_INFO is true, - generate debug info for them; otherwise don't. */ - -void -declare_vars (tree vars, gimple *gs, bool debug_info) -{ - tree last = vars; - if (last) - { - tree temps, block; - - gbind *scope = as_a <gbind *> (gs); - - temps = nreverse (last); - - block = gimple_bind_block (scope); - gcc_assert (!block || TREE_CODE (block) == BLOCK); - if (!block || !debug_info) - { - DECL_CHAIN (last) = gimple_bind_vars (scope); - gimple_bind_set_vars (scope, temps); - } - else - { - /* We need to attach the nodes both to the BIND_EXPR and to its - associated BLOCK for debugging purposes. The key point here - is that the BLOCK_VARS of the BIND_EXPR_BLOCK of a BIND_EXPR - is a subchain of the BIND_EXPR_VARS of the BIND_EXPR. */ - if (BLOCK_VARS (block)) - BLOCK_VARS (block) = chainon (BLOCK_VARS (block), temps); - else - { - gimple_bind_set_vars (scope, - chainon (gimple_bind_vars (scope), temps)); - BLOCK_VARS (block) = temps; - } - } - } -} - -/* For VAR a VAR_DECL of variable size, try to find a constant upper bound - for the size and adjust DECL_SIZE/DECL_SIZE_UNIT accordingly. Abort if - no such upper bound can be obtained. */ - -static void -force_constant_size (tree var) -{ - /* The only attempt we make is by querying the maximum size of objects - of the variable's type. */ - - HOST_WIDE_INT max_size; - - gcc_assert (VAR_P (var)); - - max_size = max_int_size_in_bytes (TREE_TYPE (var)); - - gcc_assert (max_size >= 0); - - DECL_SIZE_UNIT (var) - = build_int_cst (TREE_TYPE (DECL_SIZE_UNIT (var)), max_size); - DECL_SIZE (var) - = build_int_cst (TREE_TYPE (DECL_SIZE (var)), max_size * BITS_PER_UNIT); -} - -/* Push the temporary variable TMP into the current binding. */ - -void -gimple_add_tmp_var_fn (struct function *fn, tree tmp) -{ - gcc_assert (!DECL_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp)); - - /* Later processing assumes that the object size is constant, which might - not be true at this point. Force the use of a constant upper bound in - this case. */ - if (!tree_fits_poly_uint64_p (DECL_SIZE_UNIT (tmp))) - force_constant_size (tmp); - - DECL_CONTEXT (tmp) = fn->decl; - DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1; - - record_vars_into (tmp, fn->decl); -} - -/* Push the temporary variable TMP into the current binding. */ - -void -gimple_add_tmp_var (tree tmp) -{ - gcc_assert (!DECL_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp)); - - /* Later processing assumes that the object size is constant, which might - not be true at this point. Force the use of a constant upper bound in - this case. */ - if (!tree_fits_poly_uint64_p (DECL_SIZE_UNIT (tmp))) - force_constant_size (tmp); - - DECL_CONTEXT (tmp) = current_function_decl; - DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1; - - if (gimplify_ctxp) - { - DECL_CHAIN (tmp) = gimplify_ctxp->temps; - gimplify_ctxp->temps = tmp; - - /* Mark temporaries local within the nearest enclosing parallel. */ - if (gimplify_omp_ctxp) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - int flag = GOVD_LOCAL | GOVD_SEEN; - while (ctx - && (ctx->region_type == ORT_WORKSHARE - || ctx->region_type == ORT_TASKGROUP - || ctx->region_type == ORT_SIMD - || ctx->region_type == ORT_ACC)) - { - if (ctx->region_type == ORT_SIMD - && TREE_ADDRESSABLE (tmp) - && !TREE_STATIC (tmp)) - { - if (TREE_CODE (DECL_SIZE_UNIT (tmp)) != INTEGER_CST) - ctx->add_safelen1 = true; - else if (ctx->in_for_exprs) - flag = GOVD_PRIVATE; - else - flag = GOVD_PRIVATE | GOVD_SEEN; - break; - } - ctx = ctx->outer_context; - } - if (ctx) - omp_add_variable (ctx, tmp, flag); - } - } - else if (cfun) - record_vars (tmp); - else - { - gimple_seq body_seq; - - /* This case is for nested functions. We need to expose the locals - they create. */ - body_seq = gimple_body (current_function_decl); - declare_vars (tmp, gimple_seq_first_stmt (body_seq), false); - } -} - - - -/* This page contains routines to unshare tree nodes, i.e. to duplicate tree - nodes that are referenced more than once in GENERIC functions. This is - necessary because gimplification (translation into GIMPLE) is performed - by modifying tree nodes in-place, so gimplication of a shared node in a - first context could generate an invalid GIMPLE form in a second context. - - This is achieved with a simple mark/copy/unmark algorithm that walks the - GENERIC representation top-down, marks nodes with TREE_VISITED the first - time it encounters them, duplicates them if they already have TREE_VISITED - set, and finally removes the TREE_VISITED marks it has set. - - The algorithm works only at the function level, i.e. it generates a GENERIC - representation of a function with no nodes shared within the function when - passed a GENERIC function (except for nodes that are allowed to be shared). - - At the global level, it is also necessary to unshare tree nodes that are - referenced in more than one function, for the same aforementioned reason. - This requires some cooperation from the front-end. There are 2 strategies: - - 1. Manual unsharing. The front-end needs to call unshare_expr on every - expression that might end up being shared across functions. - - 2. Deep unsharing. This is an extension of regular unsharing. Instead - of calling unshare_expr on expressions that might be shared across - functions, the front-end pre-marks them with TREE_VISITED. This will - ensure that they are unshared on the first reference within functions - when the regular unsharing algorithm runs. The counterpart is that - this algorithm must look deeper than for manual unsharing, which is - specified by LANG_HOOKS_DEEP_UNSHARING. - - If there are only few specific cases of node sharing across functions, it is - probably easier for a front-end to unshare the expressions manually. On the - contrary, if the expressions generated at the global level are as widespread - as expressions generated within functions, deep unsharing is very likely the - way to go. */ - -/* Similar to copy_tree_r but do not copy SAVE_EXPR or TARGET_EXPR nodes. - These nodes model computations that must be done once. If we were to - unshare something like SAVE_EXPR(i++), the gimplification process would - create wrong code. However, if DATA is non-null, it must hold a pointer - set that is used to unshare the subtrees of these nodes. */ - -static tree -mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - enum tree_code code = TREE_CODE (t); - - /* Do not copy SAVE_EXPR, TARGET_EXPR or BIND_EXPR nodes themselves, but - copy their subtrees if we can make sure to do it only once. */ - if (code == SAVE_EXPR || code == TARGET_EXPR || code == BIND_EXPR) - { - if (data && !((hash_set<tree> *)data)->add (t)) - ; - else - *walk_subtrees = 0; - } - - /* Stop at types, decls, constants like copy_tree_r. */ - else if (TREE_CODE_CLASS (code) == tcc_type - || TREE_CODE_CLASS (code) == tcc_declaration - || TREE_CODE_CLASS (code) == tcc_constant) - *walk_subtrees = 0; - - /* Cope with the statement expression extension. */ - else if (code == STATEMENT_LIST) - ; - - /* Leave the bulk of the work to copy_tree_r itself. */ - else - copy_tree_r (tp, walk_subtrees, NULL); - - return NULL_TREE; -} - -/* Callback for walk_tree to unshare most of the shared trees rooted at *TP. - If *TP has been visited already, then *TP is deeply copied by calling - mostly_copy_tree_r. DATA is passed to mostly_copy_tree_r unmodified. */ - -static tree -copy_if_shared_r (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - enum tree_code code = TREE_CODE (t); - - /* Skip types, decls, and constants. But we do want to look at their - types and the bounds of types. Mark them as visited so we properly - unmark their subtrees on the unmark pass. If we've already seen them, - don't look down further. */ - if (TREE_CODE_CLASS (code) == tcc_type - || TREE_CODE_CLASS (code) == tcc_declaration - || TREE_CODE_CLASS (code) == tcc_constant) - { - if (TREE_VISITED (t)) - *walk_subtrees = 0; - else - TREE_VISITED (t) = 1; - } - - /* If this node has been visited already, unshare it and don't look - any deeper. */ - else if (TREE_VISITED (t)) - { - walk_tree (tp, mostly_copy_tree_r, data, NULL); - *walk_subtrees = 0; - } - - /* Otherwise, mark the node as visited and keep looking. */ - else - TREE_VISITED (t) = 1; - - return NULL_TREE; -} - -/* Unshare most of the shared trees rooted at *TP. DATA is passed to the - copy_if_shared_r callback unmodified. */ - -void -copy_if_shared (tree *tp, void *data) -{ - walk_tree (tp, copy_if_shared_r, data, NULL); -} - -/* Unshare all the trees in the body of FNDECL, as well as in the bodies of - any nested functions. */ - -static void -unshare_body (tree fndecl) -{ - struct cgraph_node *cgn = cgraph_node::get (fndecl); - /* If the language requires deep unsharing, we need a pointer set to make - sure we don't repeatedly unshare subtrees of unshareable nodes. */ - hash_set<tree> *visited - = lang_hooks.deep_unsharing ? new hash_set<tree> : NULL; - - copy_if_shared (&DECL_SAVED_TREE (fndecl), visited); - copy_if_shared (&DECL_SIZE (DECL_RESULT (fndecl)), visited); - copy_if_shared (&DECL_SIZE_UNIT (DECL_RESULT (fndecl)), visited); - - delete visited; - - if (cgn) - for (cgn = first_nested_function (cgn); cgn; - cgn = next_nested_function (cgn)) - unshare_body (cgn->decl); -} - -/* Callback for walk_tree to unmark the visited trees rooted at *TP. - Subtrees are walked until the first unvisited node is encountered. */ - -static tree -unmark_visited_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) -{ - tree t = *tp; - - /* If this node has been visited, unmark it and keep looking. */ - if (TREE_VISITED (t)) - TREE_VISITED (t) = 0; - - /* Otherwise, don't look any deeper. */ - else - *walk_subtrees = 0; - - return NULL_TREE; -} - -/* Unmark the visited trees rooted at *TP. */ - -static inline void -unmark_visited (tree *tp) -{ - walk_tree (tp, unmark_visited_r, NULL, NULL); -} - -/* Likewise, but mark all trees as not visited. */ - -static void -unvisit_body (tree fndecl) -{ - struct cgraph_node *cgn = cgraph_node::get (fndecl); - - unmark_visited (&DECL_SAVED_TREE (fndecl)); - unmark_visited (&DECL_SIZE (DECL_RESULT (fndecl))); - unmark_visited (&DECL_SIZE_UNIT (DECL_RESULT (fndecl))); - - if (cgn) - for (cgn = first_nested_function (cgn); - cgn; cgn = next_nested_function (cgn)) - unvisit_body (cgn->decl); -} - -/* Unconditionally make an unshared copy of EXPR. This is used when using - stored expressions which span multiple functions, such as BINFO_VTABLE, - as the normal unsharing process can't tell that they're shared. */ - -tree -unshare_expr (tree expr) -{ - walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); - return expr; -} - -/* Worker for unshare_expr_without_location. */ - -static tree -prune_expr_location (tree *tp, int *walk_subtrees, void *) -{ - if (EXPR_P (*tp)) - SET_EXPR_LOCATION (*tp, UNKNOWN_LOCATION); - else - *walk_subtrees = 0; - return NULL_TREE; -} - -/* Similar to unshare_expr but also prune all expression locations - from EXPR. */ - -tree -unshare_expr_without_location (tree expr) -{ - walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); - if (EXPR_P (expr)) - walk_tree (&expr, prune_expr_location, NULL, NULL); - return expr; -} - -/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has - one, OR_ELSE otherwise. The location of a STATEMENT_LISTs - comprising at least one DEBUG_BEGIN_STMT followed by exactly one - EXPR is the location of the EXPR. */ - -static location_t -rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION) -{ - if (!expr) - return or_else; - - if (EXPR_HAS_LOCATION (expr)) - return EXPR_LOCATION (expr); - - if (TREE_CODE (expr) != STATEMENT_LIST) - return or_else; - - tree_stmt_iterator i = tsi_start (expr); - - bool found = false; - while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) - { - found = true; - tsi_next (&i); - } - - if (!found || !tsi_one_before_end_p (i)) - return or_else; - - return rexpr_location (tsi_stmt (i), or_else); -} - -/* Return TRUE iff EXPR (maybe recursively) has a location; see - rexpr_location for the potential recursion. */ - -static inline bool -rexpr_has_location (tree expr) -{ - return rexpr_location (expr) != UNKNOWN_LOCATION; -} - - -/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both - contain statements and have a value. Assign its value to a temporary - and give it void_type_node. Return the temporary, or NULL_TREE if - WRAPPER was already void. */ - -tree -voidify_wrapper_expr (tree wrapper, tree temp) -{ - tree type = TREE_TYPE (wrapper); - if (type && !VOID_TYPE_P (type)) - { - tree *p; - - /* Set p to point to the body of the wrapper. Loop until we find - something that isn't a wrapper. */ - for (p = &wrapper; p && *p; ) - { - switch (TREE_CODE (*p)) - { - case BIND_EXPR: - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - /* For a BIND_EXPR, the body is operand 1. */ - p = &BIND_EXPR_BODY (*p); - break; - - case CLEANUP_POINT_EXPR: - case TRY_FINALLY_EXPR: - case TRY_CATCH_EXPR: - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - p = &TREE_OPERAND (*p, 0); - break; - - case STATEMENT_LIST: - { - tree_stmt_iterator i = tsi_last (*p); - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i); - } - break; - - case COMPOUND_EXPR: - /* Advance to the last statement. Set all container types to - void. */ - for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1)) - { - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - } - break; - - case TRANSACTION_EXPR: - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - p = &TRANSACTION_EXPR_BODY (*p); - break; - - default: - /* Assume that any tree upon which voidify_wrapper_expr is - directly called is a wrapper, and that its body is op0. */ - if (p == &wrapper) - { - TREE_SIDE_EFFECTS (*p) = 1; - TREE_TYPE (*p) = void_type_node; - p = &TREE_OPERAND (*p, 0); - break; - } - goto out; - } - } - - out: - if (p == NULL || IS_EMPTY_STMT (*p)) - temp = NULL_TREE; - else if (temp) - { - /* The wrapper is on the RHS of an assignment that we're pushing - down. */ - gcc_assert (TREE_CODE (temp) == INIT_EXPR - || TREE_CODE (temp) == MODIFY_EXPR); - TREE_OPERAND (temp, 1) = *p; - *p = temp; - } - else - { - temp = create_tmp_var (type, "retval"); - *p = build2 (INIT_EXPR, type, temp, *p); - } - - return temp; - } - - return NULL_TREE; -} - -/* Prepare calls to builtins to SAVE and RESTORE the stack as well as - a temporary through which they communicate. */ - -static void -build_stack_save_restore (gcall **save, gcall **restore) -{ - tree tmp_var; - - *save = gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_SAVE), 0); - tmp_var = create_tmp_var (ptr_type_node, "saved_stack"); - gimple_call_set_lhs (*save, tmp_var); - - *restore - = gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_RESTORE), - 1, tmp_var); -} - -/* Generate IFN_ASAN_MARK call that poisons shadow of a for DECL variable. */ - -static tree -build_asan_poison_call_expr (tree decl) -{ - /* Do not poison variables that have size equal to zero. */ - tree unit_size = DECL_SIZE_UNIT (decl); - if (zerop (unit_size)) - return NULL_TREE; - - tree base = build_fold_addr_expr (decl); - - return build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_ASAN_MARK, - void_type_node, 3, - build_int_cst (integer_type_node, - ASAN_MARK_POISON), - base, unit_size); -} - -/* Generate IFN_ASAN_MARK call that would poison or unpoison, depending - on POISON flag, shadow memory of a DECL variable. The call will be - put on location identified by IT iterator, where BEFORE flag drives - position where the stmt will be put. */ - -static void -asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it, - bool before) -{ - tree unit_size = DECL_SIZE_UNIT (decl); - tree base = build_fold_addr_expr (decl); - - /* Do not poison variables that have size equal to zero. */ - if (zerop (unit_size)) - return; - - /* It's necessary to have all stack variables aligned to ASAN granularity - bytes. */ - gcc_assert (!hwasan_sanitize_p () || hwasan_sanitize_stack_p ()); - unsigned shadow_granularity - = hwasan_sanitize_p () ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY; - if (DECL_ALIGN_UNIT (decl) <= shadow_granularity) - SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity); - - HOST_WIDE_INT flags = poison ? ASAN_MARK_POISON : ASAN_MARK_UNPOISON; - - gimple *g - = gimple_build_call_internal (IFN_ASAN_MARK, 3, - build_int_cst (integer_type_node, flags), - base, unit_size); - - if (before) - gsi_insert_before (it, g, GSI_NEW_STMT); - else - gsi_insert_after (it, g, GSI_NEW_STMT); -} - -/* Generate IFN_ASAN_MARK internal call that depending on POISON flag - either poisons or unpoisons a DECL. Created statement is appended - to SEQ_P gimple sequence. */ - -static void -asan_poison_variable (tree decl, bool poison, gimple_seq *seq_p) -{ - gimple_stmt_iterator it = gsi_last (*seq_p); - bool before = false; - - if (gsi_end_p (it)) - before = true; - - asan_poison_variable (decl, poison, &it, before); -} - -/* Sort pair of VAR_DECLs A and B by DECL_UID. */ - -static int -sort_by_decl_uid (const void *a, const void *b) -{ - const tree *t1 = (const tree *)a; - const tree *t2 = (const tree *)b; - - int uid1 = DECL_UID (*t1); - int uid2 = DECL_UID (*t2); - - if (uid1 < uid2) - return -1; - else if (uid1 > uid2) - return 1; - else - return 0; -} - -/* Generate IFN_ASAN_MARK internal call for all VARIABLES - depending on POISON flag. Created statement is appended - to SEQ_P gimple sequence. */ - -static void -asan_poison_variables (hash_set<tree> *variables, bool poison, gimple_seq *seq_p) -{ - unsigned c = variables->elements (); - if (c == 0) - return; - - auto_vec<tree> sorted_variables (c); - - for (hash_set<tree>::iterator it = variables->begin (); - it != variables->end (); ++it) - sorted_variables.safe_push (*it); - - sorted_variables.qsort (sort_by_decl_uid); - - unsigned i; - tree var; - FOR_EACH_VEC_ELT (sorted_variables, i, var) - { - asan_poison_variable (var, poison, seq_p); - - /* Add use_after_scope_memory attribute for the variable in order - to prevent re-written into SSA. */ - if (!lookup_attribute (ASAN_USE_AFTER_SCOPE_ATTRIBUTE, - DECL_ATTRIBUTES (var))) - DECL_ATTRIBUTES (var) - = tree_cons (get_identifier (ASAN_USE_AFTER_SCOPE_ATTRIBUTE), - integer_one_node, - DECL_ATTRIBUTES (var)); - } -} - -/* Gimplify a BIND_EXPR. Just voidify and recurse. */ - -static enum gimplify_status -gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) -{ - tree bind_expr = *expr_p; - bool old_keep_stack = gimplify_ctxp->keep_stack; - bool old_save_stack = gimplify_ctxp->save_stack; - tree t; - gbind *bind_stmt; - gimple_seq body, cleanup; - gcall *stack_save; - location_t start_locus = 0, end_locus = 0; - tree ret_clauses = NULL; - - tree temp = voidify_wrapper_expr (bind_expr, NULL); - - /* Mark variables seen in this bind expr. */ - for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t)) - { - if (VAR_P (t)) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - - /* Mark variable as local. */ - if (ctx && ctx->region_type != ORT_NONE && !DECL_EXTERNAL (t)) - { - if (! DECL_SEEN_IN_BIND_EXPR_P (t) - || splay_tree_lookup (ctx->variables, - (splay_tree_key) t) == NULL) - { - int flag = GOVD_LOCAL; - if (ctx->region_type == ORT_SIMD - && TREE_ADDRESSABLE (t) - && !TREE_STATIC (t)) - { - if (TREE_CODE (DECL_SIZE_UNIT (t)) != INTEGER_CST) - ctx->add_safelen1 = true; - else - flag = GOVD_PRIVATE; - } - omp_add_variable (ctx, t, flag | GOVD_SEEN); - } - /* Static locals inside of target construct or offloaded - routines need to be "omp declare target". */ - if (TREE_STATIC (t)) - for (; ctx; ctx = ctx->outer_context) - if ((ctx->region_type & ORT_TARGET) != 0) - { - if (!lookup_attribute ("omp declare target", - DECL_ATTRIBUTES (t))) - { - tree id = get_identifier ("omp declare target"); - DECL_ATTRIBUTES (t) - = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); - varpool_node *node = varpool_node::get (t); - if (node) - { - node->offloadable = 1; - if (ENABLE_OFFLOADING && !DECL_EXTERNAL (t)) - { - g->have_offload = true; - if (!in_lto_p) - vec_safe_push (offload_vars, t); - } - } - } - break; - } - } - - DECL_SEEN_IN_BIND_EXPR_P (t) = 1; - - if (DECL_HARD_REGISTER (t) && !is_global_var (t) && cfun) - cfun->has_local_explicit_reg_vars = true; - } - } - - bind_stmt = gimple_build_bind (BIND_EXPR_VARS (bind_expr), NULL, - BIND_EXPR_BLOCK (bind_expr)); - gimple_push_bind_expr (bind_stmt); - - gimplify_ctxp->keep_stack = false; - gimplify_ctxp->save_stack = false; - - /* Gimplify the body into the GIMPLE_BIND tuple's body. */ - body = NULL; - gimplify_stmt (&BIND_EXPR_BODY (bind_expr), &body); - gimple_bind_set_body (bind_stmt, body); - - /* Source location wise, the cleanup code (stack_restore and clobbers) - belongs to the end of the block, so propagate what we have. The - stack_save operation belongs to the beginning of block, which we can - infer from the bind_expr directly if the block has no explicit - assignment. */ - if (BIND_EXPR_BLOCK (bind_expr)) - { - end_locus = BLOCK_SOURCE_END_LOCATION (BIND_EXPR_BLOCK (bind_expr)); - start_locus = BLOCK_SOURCE_LOCATION (BIND_EXPR_BLOCK (bind_expr)); - } - if (start_locus == 0) - start_locus = EXPR_LOCATION (bind_expr); - - cleanup = NULL; - stack_save = NULL; - - /* If the code both contains VLAs and calls alloca, then we cannot reclaim - the stack space allocated to the VLAs. */ - if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack) - { - gcall *stack_restore; - - /* Save stack on entry and restore it on exit. Add a try_finally - block to achieve this. */ - build_stack_save_restore (&stack_save, &stack_restore); - - gimple_set_location (stack_save, start_locus); - gimple_set_location (stack_restore, end_locus); - - gimplify_seq_add_stmt (&cleanup, stack_restore); - } - - /* Add clobbers for all variables that go out of scope. */ - for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t)) - { - if (VAR_P (t) - && !is_global_var (t) - && DECL_CONTEXT (t) == current_function_decl) - { - if (!DECL_HARD_REGISTER (t) - && !TREE_THIS_VOLATILE (t) - && !DECL_HAS_VALUE_EXPR_P (t) - /* Only care for variables that have to be in memory. Others - will be rewritten into SSA names, hence moved to the - top-level. */ - && !is_gimple_reg (t) - && flag_stack_reuse != SR_NONE) - { - tree clobber = build_clobber (TREE_TYPE (t)); - gimple *clobber_stmt; - clobber_stmt = gimple_build_assign (t, clobber); - gimple_set_location (clobber_stmt, end_locus); - gimplify_seq_add_stmt (&cleanup, clobber_stmt); - } - - if (flag_openacc && oacc_declare_returns != NULL) - { - tree key = t; - if (DECL_HAS_VALUE_EXPR_P (key)) - { - key = DECL_VALUE_EXPR (key); - if (TREE_CODE (key) == INDIRECT_REF) - key = TREE_OPERAND (key, 0); - } - tree *c = oacc_declare_returns->get (key); - if (c != NULL) - { - if (ret_clauses) - OMP_CLAUSE_CHAIN (*c) = ret_clauses; - - ret_clauses = unshare_expr (*c); - - oacc_declare_returns->remove (key); - - if (oacc_declare_returns->is_empty ()) - { - delete oacc_declare_returns; - oacc_declare_returns = NULL; - } - } - } - } - - if (asan_poisoned_variables != NULL - && asan_poisoned_variables->contains (t)) - { - asan_poisoned_variables->remove (t); - asan_poison_variable (t, true, &cleanup); - } - - if (gimplify_ctxp->live_switch_vars != NULL - && gimplify_ctxp->live_switch_vars->contains (t)) - gimplify_ctxp->live_switch_vars->remove (t); - } - - if (ret_clauses) - { - gomp_target *stmt; - gimple_stmt_iterator si = gsi_start (cleanup); - - stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_OACC_DECLARE, - ret_clauses); - gsi_insert_seq_before_without_update (&si, stmt, GSI_NEW_STMT); - } - - if (cleanup) - { - gtry *gs; - gimple_seq new_body; - - new_body = NULL; - gs = gimple_build_try (gimple_bind_body (bind_stmt), cleanup, - GIMPLE_TRY_FINALLY); - - if (stack_save) - gimplify_seq_add_stmt (&new_body, stack_save); - gimplify_seq_add_stmt (&new_body, gs); - gimple_bind_set_body (bind_stmt, new_body); - } - - /* keep_stack propagates all the way up to the outermost BIND_EXPR. */ - if (!gimplify_ctxp->keep_stack) - gimplify_ctxp->keep_stack = old_keep_stack; - gimplify_ctxp->save_stack = old_save_stack; - - gimple_pop_bind_expr (); - - gimplify_seq_add_stmt (pre_p, bind_stmt); - - if (temp) - { - *expr_p = temp; - return GS_OK; - } - - *expr_p = NULL_TREE; - return GS_ALL_DONE; -} - -/* Maybe add early return predict statement to PRE_P sequence. */ - -static void -maybe_add_early_return_predict_stmt (gimple_seq *pre_p) -{ - /* If we are not in a conditional context, add PREDICT statement. */ - if (gimple_conditional_context ()) - { - gimple *predict = gimple_build_predict (PRED_TREE_EARLY_RETURN, - NOT_TAKEN); - gimplify_seq_add_stmt (pre_p, predict); - } -} - -/* Gimplify a RETURN_EXPR. If the expression to be returned is not a - GIMPLE value, it is assigned to a new temporary and the statement is - re-written to return the temporary. - - PRE_P points to the sequence where side effects that must happen before - STMT should be stored. */ - -static enum gimplify_status -gimplify_return_expr (tree stmt, gimple_seq *pre_p) -{ - greturn *ret; - tree ret_expr = TREE_OPERAND (stmt, 0); - tree result_decl, result; - - if (ret_expr == error_mark_node) - return GS_ERROR; - - if (!ret_expr - || TREE_CODE (ret_expr) == RESULT_DECL) - { - maybe_add_early_return_predict_stmt (pre_p); - greturn *ret = gimple_build_return (ret_expr); - copy_warning (ret, stmt); - gimplify_seq_add_stmt (pre_p, ret); - return GS_ALL_DONE; - } - - if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) - result_decl = NULL_TREE; - else if (TREE_CODE (ret_expr) == COMPOUND_EXPR) - { - /* Used in C++ for handling EH cleanup of the return value if a local - cleanup throws. Assume the front-end knows what it's doing. */ - result_decl = DECL_RESULT (current_function_decl); - /* But crash if we end up trying to modify ret_expr below. */ - ret_expr = NULL_TREE; - } - else - { - result_decl = TREE_OPERAND (ret_expr, 0); - - /* See through a return by reference. */ - if (TREE_CODE (result_decl) == INDIRECT_REF) - result_decl = TREE_OPERAND (result_decl, 0); - - gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR - || TREE_CODE (ret_expr) == INIT_EXPR) - && TREE_CODE (result_decl) == RESULT_DECL); - } - - /* If aggregate_value_p is true, then we can return the bare RESULT_DECL. - Recall that aggregate_value_p is FALSE for any aggregate type that is - returned in registers. If we're returning values in registers, then - we don't want to extend the lifetime of the RESULT_DECL, particularly - across another call. In addition, for those aggregates for which - hard_function_value generates a PARALLEL, we'll die during normal - expansion of structure assignments; there's special code in expand_return - to handle this case that does not exist in expand_expr. */ - if (!result_decl) - result = NULL_TREE; - else if (aggregate_value_p (result_decl, TREE_TYPE (current_function_decl))) - { - if (!poly_int_tree_p (DECL_SIZE (result_decl))) - { - if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (result_decl))) - gimplify_type_sizes (TREE_TYPE (result_decl), pre_p); - /* Note that we don't use gimplify_vla_decl because the RESULT_DECL - should be effectively allocated by the caller, i.e. all calls to - this function must be subject to the Return Slot Optimization. */ - gimplify_one_sizepos (&DECL_SIZE (result_decl), pre_p); - gimplify_one_sizepos (&DECL_SIZE_UNIT (result_decl), pre_p); - } - result = result_decl; - } - else if (gimplify_ctxp->return_temp) - result = gimplify_ctxp->return_temp; - else - { - result = create_tmp_reg (TREE_TYPE (result_decl)); - - /* ??? With complex control flow (usually involving abnormal edges), - we can wind up warning about an uninitialized value for this. Due - to how this variable is constructed and initialized, this is never - true. Give up and never warn. */ - suppress_warning (result, OPT_Wuninitialized); - - gimplify_ctxp->return_temp = result; - } - - /* Smash the lhs of the MODIFY_EXPR to the temporary we plan to use. - Then gimplify the whole thing. */ - if (result != result_decl) - TREE_OPERAND (ret_expr, 0) = result; - - gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p); - - maybe_add_early_return_predict_stmt (pre_p); - ret = gimple_build_return (result); - copy_warning (ret, stmt); - gimplify_seq_add_stmt (pre_p, ret); - - return GS_ALL_DONE; -} - -/* Gimplify a variable-length array DECL. */ - -static void -gimplify_vla_decl (tree decl, gimple_seq *seq_p) -{ - /* This is a variable-sized decl. Simplify its size and mark it - for deferred expansion. */ - tree t, addr, ptr_type; - - gimplify_one_sizepos (&DECL_SIZE (decl), seq_p); - gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), seq_p); - - /* Don't mess with a DECL_VALUE_EXPR set by the front-end. */ - if (DECL_HAS_VALUE_EXPR_P (decl)) - return; - - /* All occurrences of this decl in final gimplified code will be - replaced by indirection. Setting DECL_VALUE_EXPR does two - things: First, it lets the rest of the gimplifier know what - replacement to use. Second, it lets the debug info know - where to find the value. */ - ptr_type = build_pointer_type (TREE_TYPE (decl)); - addr = create_tmp_var (ptr_type, get_name (decl)); - DECL_IGNORED_P (addr) = 0; - t = build_fold_indirect_ref (addr); - TREE_THIS_NOTRAP (t) = 1; - SET_DECL_VALUE_EXPR (decl, t); - DECL_HAS_VALUE_EXPR_P (decl) = 1; - - t = build_alloca_call_expr (DECL_SIZE_UNIT (decl), DECL_ALIGN (decl), - max_int_size_in_bytes (TREE_TYPE (decl))); - /* The call has been built for a variable-sized object. */ - CALL_ALLOCA_FOR_VAR_P (t) = 1; - t = fold_convert (ptr_type, t); - t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); - - gimplify_and_add (t, seq_p); - - /* Record the dynamic allocation associated with DECL if requested. */ - if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC) - record_dynamic_alloc (decl); -} - -/* A helper function to be called via walk_tree. Mark all labels under *TP - as being forced. To be called for DECL_INITIAL of static variables. */ - -static tree -force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) -{ - if (TYPE_P (*tp)) - *walk_subtrees = 0; - if (TREE_CODE (*tp) == LABEL_DECL) - { - FORCED_LABEL (*tp) = 1; - cfun->has_forced_label_in_static = 1; - } - - return NULL_TREE; -} - -/* Generate an initialization to automatic variable DECL based on INIT_TYPE. - Build a call to internal const function DEFERRED_INIT: - 1st argument: SIZE of the DECL; - 2nd argument: INIT_TYPE; - 3rd argument: NAME of the DECL; - - as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL). */ - -static void -gimple_add_init_for_auto_var (tree decl, - enum auto_init_type init_type, - gimple_seq *seq_p) -{ - gcc_assert (auto_var_p (decl)); - gcc_assert (init_type > AUTO_INIT_UNINITIALIZED); - location_t loc = EXPR_LOCATION (decl); - tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl)); - - tree init_type_node - = build_int_cst (integer_type_node, (int) init_type); - - tree decl_name = NULL_TREE; - if (DECL_NAME (decl)) - - decl_name = build_string_literal (IDENTIFIER_LENGTH (DECL_NAME (decl)) + 1, - IDENTIFIER_POINTER (DECL_NAME (decl))); - - else - { - char *decl_name_anonymous = xasprintf ("D.%u", DECL_UID (decl)); - decl_name = build_string_literal (strlen (decl_name_anonymous) + 1, - decl_name_anonymous); - free (decl_name_anonymous); - } - - tree call = build_call_expr_internal_loc (loc, IFN_DEFERRED_INIT, - TREE_TYPE (decl), 3, - decl_size, init_type_node, - decl_name); - - gimplify_assign (decl, call, seq_p); -} - -/* Generate padding initialization for automatic vairable DECL. - C guarantees that brace-init with fewer initializers than members - aggregate will initialize the rest of the aggregate as-if it were - static initialization. In turn static initialization guarantees - that padding is initialized to zero. So, we always initialize paddings - to zeroes regardless INIT_TYPE. - To do the padding initialization, we insert a call to - __builtin_clear_padding (&decl, 0, for_auto_init = true). - Note, we add an additional dummy argument for __builtin_clear_padding, - 'for_auto_init' to distinguish whether this call is for automatic - variable initialization or not. - */ -static void -gimple_add_padding_init_for_auto_var (tree decl, bool is_vla, - gimple_seq *seq_p) -{ - tree addr_of_decl = NULL_TREE; - bool for_auto_init = true; - tree fn = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING); - - if (is_vla) - { - /* The temporary address variable for this vla should be - created in gimplify_vla_decl. */ - gcc_assert (DECL_HAS_VALUE_EXPR_P (decl)); - gcc_assert (TREE_CODE (DECL_VALUE_EXPR (decl)) == INDIRECT_REF); - addr_of_decl = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0); - } - else - { - mark_addressable (decl); - addr_of_decl = build_fold_addr_expr (decl); - } - - gimple *call = gimple_build_call (fn, - 3, addr_of_decl, - build_zero_cst (TREE_TYPE (addr_of_decl)), - build_int_cst (integer_type_node, - (int) for_auto_init)); - gimplify_seq_add_stmt (seq_p, call); -} - -/* Return true if the DECL need to be automaticly initialized by the - compiler. */ -static bool -is_var_need_auto_init (tree decl) -{ - if (auto_var_p (decl) - && (TREE_CODE (decl) != VAR_DECL - || !DECL_HARD_REGISTER (decl)) - && (flag_auto_var_init > AUTO_INIT_UNINITIALIZED) - && (!lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))) - && !OPAQUE_TYPE_P (TREE_TYPE (decl)) - && !is_empty_type (TREE_TYPE (decl))) - return true; - return false; -} - -/* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation - and initialization explicit. */ - -static enum gimplify_status -gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) -{ - tree stmt = *stmt_p; - tree decl = DECL_EXPR_DECL (stmt); - - *stmt_p = NULL_TREE; - - if (TREE_TYPE (decl) == error_mark_node) - return GS_ERROR; - - if ((TREE_CODE (decl) == TYPE_DECL - || VAR_P (decl)) - && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl))) - { - gimplify_type_sizes (TREE_TYPE (decl), seq_p); - if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) - gimplify_type_sizes (TREE_TYPE (TREE_TYPE (decl)), seq_p); - } - - /* ??? DECL_ORIGINAL_TYPE is streamed for LTO so it needs to be gimplified - in case its size expressions contain problematic nodes like CALL_EXPR. */ - if (TREE_CODE (decl) == TYPE_DECL - && DECL_ORIGINAL_TYPE (decl) - && !TYPE_SIZES_GIMPLIFIED (DECL_ORIGINAL_TYPE (decl))) - { - gimplify_type_sizes (DECL_ORIGINAL_TYPE (decl), seq_p); - if (TREE_CODE (DECL_ORIGINAL_TYPE (decl)) == REFERENCE_TYPE) - gimplify_type_sizes (TREE_TYPE (DECL_ORIGINAL_TYPE (decl)), seq_p); - } - - if (VAR_P (decl) && !DECL_EXTERNAL (decl)) - { - tree init = DECL_INITIAL (decl); - bool is_vla = false; - /* Check whether a decl has FE created VALUE_EXPR here BEFORE - gimplify_vla_decl creates VALUE_EXPR for a vla decl. - If the decl has VALUE_EXPR that was created by FE (usually - C++FE), it's a proxy varaible, and FE already initialized - the VALUE_EXPR of it, we should not initialize it anymore. */ - bool decl_had_value_expr_p = DECL_HAS_VALUE_EXPR_P (decl); - - poly_uint64 size; - if (!poly_int_tree_p (DECL_SIZE_UNIT (decl), &size) - || (!TREE_STATIC (decl) - && flag_stack_check == GENERIC_STACK_CHECK - && maybe_gt (size, - (unsigned HOST_WIDE_INT) STACK_CHECK_MAX_VAR_SIZE))) - { - gimplify_vla_decl (decl, seq_p); - is_vla = true; - } - - if (asan_poisoned_variables - && !is_vla - && TREE_ADDRESSABLE (decl) - && !TREE_STATIC (decl) - && !DECL_HAS_VALUE_EXPR_P (decl) - && DECL_ALIGN (decl) <= MAX_SUPPORTED_STACK_ALIGNMENT - && dbg_cnt (asan_use_after_scope) - && !gimplify_omp_ctxp - /* GNAT introduces temporaries to hold return values of calls in - initializers of variables defined in other units, so the - declaration of the variable is discarded completely. We do not - want to issue poison calls for such dropped variables. */ - && (DECL_SEEN_IN_BIND_EXPR_P (decl) - || (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE))) - { - asan_poisoned_variables->add (decl); - asan_poison_variable (decl, false, seq_p); - if (!DECL_ARTIFICIAL (decl) && gimplify_ctxp->live_switch_vars) - gimplify_ctxp->live_switch_vars->add (decl); - } - - /* Some front ends do not explicitly declare all anonymous - artificial variables. We compensate here by declaring the - variables, though it would be better if the front ends would - explicitly declare them. */ - if (!DECL_SEEN_IN_BIND_EXPR_P (decl) - && DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE) - gimple_add_tmp_var (decl); - - if (init && init != error_mark_node) - { - if (!TREE_STATIC (decl)) - { - DECL_INITIAL (decl) = NULL_TREE; - init = build2 (INIT_EXPR, void_type_node, decl, init); - gimplify_and_add (init, seq_p); - ggc_free (init); - /* Clear TREE_READONLY if we really have an initialization. */ - if (!DECL_INITIAL (decl) - && !omp_privatize_by_reference (decl)) - TREE_READONLY (decl) = 0; - } - else - /* We must still examine initializers for static variables - as they may contain a label address. */ - walk_tree (&init, force_labels_r, NULL, NULL); - } - /* When there is no explicit initializer, if the user requested, - We should insert an artifical initializer for this automatic - variable. */ - else if (is_var_need_auto_init (decl) - && !decl_had_value_expr_p) - { - gimple_add_init_for_auto_var (decl, - flag_auto_var_init, - seq_p); - /* The expanding of a call to the above .DEFERRED_INIT will apply - block initialization to the whole space covered by this variable. - As a result, all the paddings will be initialized to zeroes - for zero initialization and 0xFE byte-repeatable patterns for - pattern initialization. - In order to make the paddings as zeroes for pattern init, We - should add a call to __builtin_clear_padding to clear the - paddings to zero in compatiple with CLANG. - We cannot insert this call if the variable is a gimple register - since __builtin_clear_padding will take the address of the - variable. As a result, if a long double/_Complex long double - variable will spilled into stack later, its padding is 0XFE. */ - if (flag_auto_var_init == AUTO_INIT_PATTERN - && !is_gimple_reg (decl) - && clear_padding_type_may_have_padding_p (TREE_TYPE (decl))) - gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p); - } - } - - return GS_ALL_DONE; -} - -/* Gimplify a LOOP_EXPR. Normally this just involves gimplifying the body - and replacing the LOOP_EXPR with goto, but if the loop contains an - EXIT_EXPR, we need to append a label for it to jump to. */ - -static enum gimplify_status -gimplify_loop_expr (tree *expr_p, gimple_seq *pre_p) -{ - tree saved_label = gimplify_ctxp->exit_label; - tree start_label = create_artificial_label (UNKNOWN_LOCATION); - - gimplify_seq_add_stmt (pre_p, gimple_build_label (start_label)); - - gimplify_ctxp->exit_label = NULL_TREE; - - gimplify_and_add (LOOP_EXPR_BODY (*expr_p), pre_p); - - gimplify_seq_add_stmt (pre_p, gimple_build_goto (start_label)); - - if (gimplify_ctxp->exit_label) - gimplify_seq_add_stmt (pre_p, - gimple_build_label (gimplify_ctxp->exit_label)); - - gimplify_ctxp->exit_label = saved_label; - - *expr_p = NULL; - return GS_ALL_DONE; -} - -/* Gimplify a statement list onto a sequence. These may be created either - by an enlightened front-end, or by shortcut_cond_expr. */ - -static enum gimplify_status -gimplify_statement_list (tree *expr_p, gimple_seq *pre_p) -{ - tree temp = voidify_wrapper_expr (*expr_p, NULL); - - tree_stmt_iterator i = tsi_start (*expr_p); - - while (!tsi_end_p (i)) - { - gimplify_stmt (tsi_stmt_ptr (i), pre_p); - tsi_delink (&i); - } - - if (temp) - { - *expr_p = temp; - return GS_OK; - } - - return GS_ALL_DONE; -} - -/* Callback for walk_gimple_seq. */ - -static tree -warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, - struct walk_stmt_info *wi) -{ - gimple *stmt = gsi_stmt (*gsi_p); - - *handled_ops_p = true; - switch (gimple_code (stmt)) - { - case GIMPLE_TRY: - /* A compiler-generated cleanup or a user-written try block. - If it's empty, don't dive into it--that would result in - worse location info. */ - if (gimple_try_eval (stmt) == NULL) - { - wi->info = stmt; - return integer_zero_node; - } - /* Fall through. */ - case GIMPLE_BIND: - case GIMPLE_CATCH: - case GIMPLE_EH_FILTER: - case GIMPLE_TRANSACTION: - /* Walk the sub-statements. */ - *handled_ops_p = false; - break; - - case GIMPLE_DEBUG: - /* Ignore these. We may generate them before declarations that - are never executed. If there's something to warn about, - there will be non-debug stmts too, and we'll catch those. */ - break; - - case GIMPLE_CALL: - if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) - { - *handled_ops_p = false; - break; - } - /* Fall through. */ - default: - /* Save the first "real" statement (not a decl/lexical scope/...). */ - wi->info = stmt; - return integer_zero_node; - } - return NULL_TREE; -} - -/* Possibly warn about unreachable statements between switch's controlling - expression and the first case. SEQ is the body of a switch expression. */ - -static void -maybe_warn_switch_unreachable (gimple_seq seq) -{ - if (!warn_switch_unreachable - /* This warning doesn't play well with Fortran when optimizations - are on. */ - || lang_GNU_Fortran () - || seq == NULL) - return; - - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - walk_gimple_seq (seq, warn_switch_unreachable_r, NULL, &wi); - gimple *stmt = (gimple *) wi.info; - - if (stmt && gimple_code (stmt) != GIMPLE_LABEL) - { - if (gimple_code (stmt) == GIMPLE_GOTO - && TREE_CODE (gimple_goto_dest (stmt)) == LABEL_DECL - && DECL_ARTIFICIAL (gimple_goto_dest (stmt))) - /* Don't warn for compiler-generated gotos. These occur - in Duff's devices, for example. */; - else - warning_at (gimple_location (stmt), OPT_Wswitch_unreachable, - "statement will never be executed"); - } -} - - -/* A label entry that pairs label and a location. */ -struct label_entry -{ - tree label; - location_t loc; -}; - -/* Find LABEL in vector of label entries VEC. */ - -static struct label_entry * -find_label_entry (const auto_vec<struct label_entry> *vec, tree label) -{ - unsigned int i; - struct label_entry *l; - - FOR_EACH_VEC_ELT (*vec, i, l) - if (l->label == label) - return l; - return NULL; -} - -/* Return true if LABEL, a LABEL_DECL, represents a case label - in a vector of labels CASES. */ - -static bool -case_label_p (const vec<tree> *cases, tree label) -{ - unsigned int i; - tree l; - - FOR_EACH_VEC_ELT (*cases, i, l) - if (CASE_LABEL (l) == label) - return true; - return false; -} - -/* Find the last nondebug statement in a scope STMT. */ - -static gimple * -last_stmt_in_scope (gimple *stmt) -{ - if (!stmt) - return NULL; - - switch (gimple_code (stmt)) - { - case GIMPLE_BIND: - { - gbind *bind = as_a <gbind *> (stmt); - stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind)); - return last_stmt_in_scope (stmt); - } - - case GIMPLE_TRY: - { - gtry *try_stmt = as_a <gtry *> (stmt); - stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt)); - gimple *last_eval = last_stmt_in_scope (stmt); - if (gimple_stmt_may_fallthru (last_eval) - && (last_eval == NULL - || !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH)) - && gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY) - { - stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt)); - return last_stmt_in_scope (stmt); - } - else - return last_eval; - } - - case GIMPLE_DEBUG: - gcc_unreachable (); - - default: - return stmt; - } -} - -/* Collect interesting labels in LABELS and return the statement preceding - another case label, or a user-defined label. Store a location useful - to give warnings at *PREVLOC (usually the location of the returned - statement or of its surrounding scope). */ - -static gimple * -collect_fallthrough_labels (gimple_stmt_iterator *gsi_p, - auto_vec <struct label_entry> *labels, - location_t *prevloc) -{ - gimple *prev = NULL; - - *prevloc = UNKNOWN_LOCATION; - do - { - if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND) - { - /* Recognize the special GIMPLE_BIND added by gimplify_switch_expr, - which starts on a GIMPLE_SWITCH and ends with a break label. - Handle that as a single statement that can fall through. */ - gbind *bind = as_a <gbind *> (gsi_stmt (*gsi_p)); - gimple *first = gimple_seq_first_stmt (gimple_bind_body (bind)); - gimple *last = gimple_seq_last_stmt (gimple_bind_body (bind)); - if (last - && gimple_code (first) == GIMPLE_SWITCH - && gimple_code (last) == GIMPLE_LABEL) - { - tree label = gimple_label_label (as_a <glabel *> (last)); - if (SWITCH_BREAK_LABEL_P (label)) - { - prev = bind; - gsi_next (gsi_p); - continue; - } - } - } - if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND - || gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_TRY) - { - /* Nested scope. Only look at the last statement of - the innermost scope. */ - location_t bind_loc = gimple_location (gsi_stmt (*gsi_p)); - gimple *last = last_stmt_in_scope (gsi_stmt (*gsi_p)); - if (last) - { - prev = last; - /* It might be a label without a location. Use the - location of the scope then. */ - if (!gimple_has_location (prev)) - *prevloc = bind_loc; - } - gsi_next (gsi_p); - continue; - } - - /* Ifs are tricky. */ - if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_COND) - { - gcond *cond_stmt = as_a <gcond *> (gsi_stmt (*gsi_p)); - tree false_lab = gimple_cond_false_label (cond_stmt); - location_t if_loc = gimple_location (cond_stmt); - - /* If we have e.g. - if (i > 1) goto <D.2259>; else goto D; - we can't do much with the else-branch. */ - if (!DECL_ARTIFICIAL (false_lab)) - break; - - /* Go on until the false label, then one step back. */ - for (; !gsi_end_p (*gsi_p); gsi_next (gsi_p)) - { - gimple *stmt = gsi_stmt (*gsi_p); - if (gimple_code (stmt) == GIMPLE_LABEL - && gimple_label_label (as_a <glabel *> (stmt)) == false_lab) - break; - } - - /* Not found? Oops. */ - if (gsi_end_p (*gsi_p)) - break; - - struct label_entry l = { false_lab, if_loc }; - labels->safe_push (l); - - /* Go to the last statement of the then branch. */ - gsi_prev (gsi_p); - - /* if (i != 0) goto <D.1759>; else goto <D.1760>; - <D.1759>: - <stmt>; - goto <D.1761>; - <D.1760>: - */ - if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO - && !gimple_has_location (gsi_stmt (*gsi_p))) - { - /* Look at the statement before, it might be - attribute fallthrough, in which case don't warn. */ - gsi_prev (gsi_p); - bool fallthru_before_dest - = gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_FALLTHROUGH); - gsi_next (gsi_p); - tree goto_dest = gimple_goto_dest (gsi_stmt (*gsi_p)); - if (!fallthru_before_dest) - { - struct label_entry l = { goto_dest, if_loc }; - labels->safe_push (l); - } - } - /* And move back. */ - gsi_next (gsi_p); - } - - /* Remember the last statement. Skip labels that are of no interest - to us. */ - if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) - { - tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (*gsi_p))); - if (find_label_entry (labels, label)) - prev = gsi_stmt (*gsi_p); - } - else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK)) - ; - else if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_PREDICT) - ; - else if (!is_gimple_debug (gsi_stmt (*gsi_p))) - prev = gsi_stmt (*gsi_p); - gsi_next (gsi_p); - } - while (!gsi_end_p (*gsi_p) - /* Stop if we find a case or a user-defined label. */ - && (gimple_code (gsi_stmt (*gsi_p)) != GIMPLE_LABEL - || !gimple_has_location (gsi_stmt (*gsi_p)))); - - if (prev && gimple_has_location (prev)) - *prevloc = gimple_location (prev); - return prev; -} - -/* Return true if the switch fallthough warning should occur. LABEL is - the label statement that we're falling through to. */ - -static bool -should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label) -{ - gimple_stmt_iterator gsi = *gsi_p; - - /* Don't warn if the label is marked with a "falls through" comment. */ - if (FALLTHROUGH_LABEL_P (label)) - return false; - - /* Don't warn for non-case labels followed by a statement: - case 0: - foo (); - label: - bar (); - as these are likely intentional. */ - if (!case_label_p (&gimplify_ctxp->case_labels, label)) - { - tree l; - while (!gsi_end_p (gsi) - && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL - && (l = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi)))) - && !case_label_p (&gimplify_ctxp->case_labels, l)) - gsi_next_nondebug (&gsi); - if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL) - return false; - } - - /* Don't warn for terminated branches, i.e. when the subsequent case labels - immediately breaks. */ - gsi = *gsi_p; - - /* Skip all immediately following labels. */ - while (!gsi_end_p (gsi) - && (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL - || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT)) - gsi_next_nondebug (&gsi); - - /* { ... something; default:; } */ - if (gsi_end_p (gsi) - /* { ... something; default: break; } or - { ... something; default: goto L; } */ - || gimple_code (gsi_stmt (gsi)) == GIMPLE_GOTO - /* { ... something; default: return; } */ - || gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN) - return false; - - return true; -} - -/* Callback for walk_gimple_seq. */ - -static tree -warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, - struct walk_stmt_info *) -{ - gimple *stmt = gsi_stmt (*gsi_p); - - *handled_ops_p = true; - switch (gimple_code (stmt)) - { - case GIMPLE_TRY: - case GIMPLE_BIND: - case GIMPLE_CATCH: - case GIMPLE_EH_FILTER: - case GIMPLE_TRANSACTION: - /* Walk the sub-statements. */ - *handled_ops_p = false; - break; - - /* Find a sequence of form: - - GIMPLE_LABEL - [...] - <may fallthru stmt> - GIMPLE_LABEL - - and possibly warn. */ - case GIMPLE_LABEL: - { - /* Found a label. Skip all immediately following labels. */ - while (!gsi_end_p (*gsi_p) - && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) - gsi_next_nondebug (gsi_p); - - /* There might be no more statements. */ - if (gsi_end_p (*gsi_p)) - return integer_zero_node; - - /* Vector of labels that fall through. */ - auto_vec <struct label_entry> labels; - location_t prevloc; - gimple *prev = collect_fallthrough_labels (gsi_p, &labels, &prevloc); - - /* There might be no more statements. */ - if (gsi_end_p (*gsi_p)) - return integer_zero_node; - - gimple *next = gsi_stmt (*gsi_p); - tree label; - /* If what follows is a label, then we may have a fallthrough. */ - if (gimple_code (next) == GIMPLE_LABEL - && gimple_has_location (next) - && (label = gimple_label_label (as_a <glabel *> (next))) - && prev != NULL) - { - struct label_entry *l; - bool warned_p = false; - auto_diagnostic_group d; - if (!should_warn_for_implicit_fallthrough (gsi_p, label)) - /* Quiet. */; - else if (gimple_code (prev) == GIMPLE_LABEL - && (label = gimple_label_label (as_a <glabel *> (prev))) - && (l = find_label_entry (&labels, label))) - warned_p = warning_at (l->loc, OPT_Wimplicit_fallthrough_, - "this statement may fall through"); - else if (!gimple_call_internal_p (prev, IFN_FALLTHROUGH) - /* Try to be clever and don't warn when the statement - can't actually fall through. */ - && gimple_stmt_may_fallthru (prev) - && prevloc != UNKNOWN_LOCATION) - warned_p = warning_at (prevloc, - OPT_Wimplicit_fallthrough_, - "this statement may fall through"); - if (warned_p) - inform (gimple_location (next), "here"); - - /* Mark this label as processed so as to prevent multiple - warnings in nested switches. */ - FALLTHROUGH_LABEL_P (label) = true; - - /* So that next warn_implicit_fallthrough_r will start looking for - a new sequence starting with this label. */ - gsi_prev (gsi_p); - } - } - break; - default: - break; - } - return NULL_TREE; -} - -/* Warn when a switch case falls through. */ - -static void -maybe_warn_implicit_fallthrough (gimple_seq seq) -{ - if (!warn_implicit_fallthrough) - return; - - /* This warning is meant for C/C++/ObjC/ObjC++ only. */ - if (!(lang_GNU_C () - || lang_GNU_CXX () - || lang_GNU_OBJC ())) - return; - - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - walk_gimple_seq (seq, warn_implicit_fallthrough_r, NULL, &wi); -} - -/* Callback for walk_gimple_seq. */ - -static tree -expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, - struct walk_stmt_info *wi) -{ - gimple *stmt = gsi_stmt (*gsi_p); - - *handled_ops_p = true; - switch (gimple_code (stmt)) - { - case GIMPLE_TRY: - case GIMPLE_BIND: - case GIMPLE_CATCH: - case GIMPLE_EH_FILTER: - case GIMPLE_TRANSACTION: - /* Walk the sub-statements. */ - *handled_ops_p = false; - break; - case GIMPLE_CALL: - if (gimple_call_internal_p (stmt, IFN_FALLTHROUGH)) - { - gsi_remove (gsi_p, true); - if (gsi_end_p (*gsi_p)) - { - *static_cast<location_t *>(wi->info) = gimple_location (stmt); - return integer_zero_node; - } - - bool found = false; - location_t loc = gimple_location (stmt); - - gimple_stmt_iterator gsi2 = *gsi_p; - stmt = gsi_stmt (gsi2); - if (gimple_code (stmt) == GIMPLE_GOTO && !gimple_has_location (stmt)) - { - /* Go on until the artificial label. */ - tree goto_dest = gimple_goto_dest (stmt); - for (; !gsi_end_p (gsi2); gsi_next (&gsi2)) - { - if (gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL - && gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2))) - == goto_dest) - break; - } - - /* Not found? Stop. */ - if (gsi_end_p (gsi2)) - break; - - /* Look one past it. */ - gsi_next (&gsi2); - } - - /* We're looking for a case label or default label here. */ - while (!gsi_end_p (gsi2)) - { - stmt = gsi_stmt (gsi2); - if (gimple_code (stmt) == GIMPLE_LABEL) - { - tree label = gimple_label_label (as_a <glabel *> (stmt)); - if (gimple_has_location (stmt) && DECL_ARTIFICIAL (label)) - { - found = true; - break; - } - } - else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) - ; - else if (!is_gimple_debug (stmt)) - /* Anything else is not expected. */ - break; - gsi_next (&gsi2); - } - if (!found) - pedwarn (loc, 0, "attribute %<fallthrough%> not preceding " - "a case label or default label"); - } - break; - default: - break; - } - return NULL_TREE; -} - -/* Expand all FALLTHROUGH () calls in SEQ. */ - -static void -expand_FALLTHROUGH (gimple_seq *seq_p) -{ - struct walk_stmt_info wi; - location_t loc; - memset (&wi, 0, sizeof (wi)); - wi.info = (void *) &loc; - walk_gimple_seq_mod (seq_p, expand_FALLTHROUGH_r, NULL, &wi); - if (wi.callback_result == integer_zero_node) - /* We've found [[fallthrough]]; at the end of a switch, which the C++ - standard says is ill-formed; see [dcl.attr.fallthrough]. */ - pedwarn (loc, 0, "attribute %<fallthrough%> not preceding " - "a case label or default label"); -} - - -/* Gimplify a SWITCH_EXPR, and collect the vector of labels it can - branch to. */ - -static enum gimplify_status -gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) -{ - tree switch_expr = *expr_p; - gimple_seq switch_body_seq = NULL; - enum gimplify_status ret; - tree index_type = TREE_TYPE (switch_expr); - if (index_type == NULL_TREE) - index_type = TREE_TYPE (SWITCH_COND (switch_expr)); - - ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, is_gimple_val, - fb_rvalue); - if (ret == GS_ERROR || ret == GS_UNHANDLED) - return ret; - - if (SWITCH_BODY (switch_expr)) - { - vec<tree> labels; - vec<tree> saved_labels; - hash_set<tree> *saved_live_switch_vars = NULL; - tree default_case = NULL_TREE; - gswitch *switch_stmt; - - /* Save old labels, get new ones from body, then restore the old - labels. Save all the things from the switch body to append after. */ - saved_labels = gimplify_ctxp->case_labels; - gimplify_ctxp->case_labels.create (8); - - /* Do not create live_switch_vars if SWITCH_BODY is not a BIND_EXPR. */ - saved_live_switch_vars = gimplify_ctxp->live_switch_vars; - tree_code body_type = TREE_CODE (SWITCH_BODY (switch_expr)); - if (body_type == BIND_EXPR || body_type == STATEMENT_LIST) - gimplify_ctxp->live_switch_vars = new hash_set<tree> (4); - else - gimplify_ctxp->live_switch_vars = NULL; - - bool old_in_switch_expr = gimplify_ctxp->in_switch_expr; - gimplify_ctxp->in_switch_expr = true; - - gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq); - - gimplify_ctxp->in_switch_expr = old_in_switch_expr; - maybe_warn_switch_unreachable (switch_body_seq); - maybe_warn_implicit_fallthrough (switch_body_seq); - /* Only do this for the outermost GIMPLE_SWITCH. */ - if (!gimplify_ctxp->in_switch_expr) - expand_FALLTHROUGH (&switch_body_seq); - - labels = gimplify_ctxp->case_labels; - gimplify_ctxp->case_labels = saved_labels; - - if (gimplify_ctxp->live_switch_vars) - { - gcc_assert (gimplify_ctxp->live_switch_vars->is_empty ()); - delete gimplify_ctxp->live_switch_vars; - } - gimplify_ctxp->live_switch_vars = saved_live_switch_vars; - - preprocess_case_label_vec_for_gimple (labels, index_type, - &default_case); - - bool add_bind = false; - if (!default_case) - { - glabel *new_default; - - default_case - = build_case_label (NULL_TREE, NULL_TREE, - create_artificial_label (UNKNOWN_LOCATION)); - if (old_in_switch_expr) - { - SWITCH_BREAK_LABEL_P (CASE_LABEL (default_case)) = 1; - add_bind = true; - } - new_default = gimple_build_label (CASE_LABEL (default_case)); - gimplify_seq_add_stmt (&switch_body_seq, new_default); - } - else if (old_in_switch_expr) - { - gimple *last = gimple_seq_last_stmt (switch_body_seq); - if (last && gimple_code (last) == GIMPLE_LABEL) - { - tree label = gimple_label_label (as_a <glabel *> (last)); - if (SWITCH_BREAK_LABEL_P (label)) - add_bind = true; - } - } - - switch_stmt = gimple_build_switch (SWITCH_COND (switch_expr), - default_case, labels); - /* For the benefit of -Wimplicit-fallthrough, if switch_body_seq - ends with a GIMPLE_LABEL holding SWITCH_BREAK_LABEL_P LABEL_DECL, - wrap the GIMPLE_SWITCH up to that GIMPLE_LABEL into a GIMPLE_BIND, - so that we can easily find the start and end of the switch - statement. */ - if (add_bind) - { - gimple_seq bind_body = NULL; - gimplify_seq_add_stmt (&bind_body, switch_stmt); - gimple_seq_add_seq (&bind_body, switch_body_seq); - gbind *bind = gimple_build_bind (NULL_TREE, bind_body, NULL_TREE); - gimple_set_location (bind, EXPR_LOCATION (switch_expr)); - gimplify_seq_add_stmt (pre_p, bind); - } - else - { - gimplify_seq_add_stmt (pre_p, switch_stmt); - gimplify_seq_add_seq (pre_p, switch_body_seq); - } - labels.release (); - } - else - gcc_unreachable (); - - return GS_ALL_DONE; -} - -/* Gimplify the LABEL_EXPR pointed to by EXPR_P. */ - -static enum gimplify_status -gimplify_label_expr (tree *expr_p, gimple_seq *pre_p) -{ - gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) - == current_function_decl); - - tree label = LABEL_EXPR_LABEL (*expr_p); - glabel *label_stmt = gimple_build_label (label); - gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); - gimplify_seq_add_stmt (pre_p, label_stmt); - - if (lookup_attribute ("cold", DECL_ATTRIBUTES (label))) - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL, - NOT_TAKEN)); - else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label))) - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL, - TAKEN)); - - return GS_ALL_DONE; -} - -/* Gimplify the CASE_LABEL_EXPR pointed to by EXPR_P. */ - -static enum gimplify_status -gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p) -{ - struct gimplify_ctx *ctxp; - glabel *label_stmt; - - /* Invalid programs can play Duff's Device type games with, for example, - #pragma omp parallel. At least in the C front end, we don't - detect such invalid branches until after gimplification, in the - diagnose_omp_blocks pass. */ - for (ctxp = gimplify_ctxp; ; ctxp = ctxp->prev_context) - if (ctxp->case_labels.exists ()) - break; - - tree label = CASE_LABEL (*expr_p); - label_stmt = gimple_build_label (label); - gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); - ctxp->case_labels.safe_push (*expr_p); - gimplify_seq_add_stmt (pre_p, label_stmt); - - if (lookup_attribute ("cold", DECL_ATTRIBUTES (label))) - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL, - NOT_TAKEN)); - else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label))) - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL, - TAKEN)); - - return GS_ALL_DONE; -} - -/* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first - if necessary. */ - -tree -build_and_jump (tree *label_p) -{ - if (label_p == NULL) - /* If there's nowhere to jump, just fall through. */ - return NULL_TREE; - - if (*label_p == NULL_TREE) - { - tree label = create_artificial_label (UNKNOWN_LOCATION); - *label_p = label; - } - - return build1 (GOTO_EXPR, void_type_node, *label_p); -} - -/* Gimplify an EXIT_EXPR by converting to a GOTO_EXPR inside a COND_EXPR. - This also involves building a label to jump to and communicating it to - gimplify_loop_expr through gimplify_ctxp->exit_label. */ - -static enum gimplify_status -gimplify_exit_expr (tree *expr_p) -{ - tree cond = TREE_OPERAND (*expr_p, 0); - tree expr; - - expr = build_and_jump (&gimplify_ctxp->exit_label); - expr = build3 (COND_EXPR, void_type_node, cond, expr, NULL_TREE); - *expr_p = expr; - - return GS_OK; -} - -/* *EXPR_P is a COMPONENT_REF being used as an rvalue. If its type is - different from its canonical type, wrap the whole thing inside a - NOP_EXPR and force the type of the COMPONENT_REF to be the canonical - type. - - The canonical type of a COMPONENT_REF is the type of the field being - referenced--unless the field is a bit-field which can be read directly - in a smaller mode, in which case the canonical type is the - sign-appropriate type corresponding to that mode. */ - -static void -canonicalize_component_ref (tree *expr_p) -{ - tree expr = *expr_p; - tree type; - - gcc_assert (TREE_CODE (expr) == COMPONENT_REF); - - if (INTEGRAL_TYPE_P (TREE_TYPE (expr))) - type = TREE_TYPE (get_unwidened (expr, NULL_TREE)); - else - type = TREE_TYPE (TREE_OPERAND (expr, 1)); - - /* One could argue that all the stuff below is not necessary for - the non-bitfield case and declare it a FE error if type - adjustment would be needed. */ - if (TREE_TYPE (expr) != type) - { -#ifdef ENABLE_TYPES_CHECKING - tree old_type = TREE_TYPE (expr); -#endif - int type_quals; - - /* We need to preserve qualifiers and propagate them from - operand 0. */ - type_quals = TYPE_QUALS (type) - | TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0))); - if (TYPE_QUALS (type) != type_quals) - type = build_qualified_type (TYPE_MAIN_VARIANT (type), type_quals); - - /* Set the type of the COMPONENT_REF to the underlying type. */ - TREE_TYPE (expr) = type; - -#ifdef ENABLE_TYPES_CHECKING - /* It is now a FE error, if the conversion from the canonical - type to the original expression type is not useless. */ - gcc_assert (useless_type_conversion_p (old_type, type)); -#endif - } -} - -/* If a NOP conversion is changing a pointer to array of foo to a pointer - to foo, embed that change in the ADDR_EXPR by converting - T array[U]; - (T *)&array - ==> - &array[L] - where L is the lower bound. For simplicity, only do this for constant - lower bound. - The constraint is that the type of &array[L] is trivially convertible - to T *. */ - -static void -canonicalize_addr_expr (tree *expr_p) -{ - tree expr = *expr_p; - tree addr_expr = TREE_OPERAND (expr, 0); - tree datype, ddatype, pddatype; - - /* We simplify only conversions from an ADDR_EXPR to a pointer type. */ - if (!POINTER_TYPE_P (TREE_TYPE (expr)) - || TREE_CODE (addr_expr) != ADDR_EXPR) - return; - - /* The addr_expr type should be a pointer to an array. */ - datype = TREE_TYPE (TREE_TYPE (addr_expr)); - if (TREE_CODE (datype) != ARRAY_TYPE) - return; - - /* The pointer to element type shall be trivially convertible to - the expression pointer type. */ - ddatype = TREE_TYPE (datype); - pddatype = build_pointer_type (ddatype); - if (!useless_type_conversion_p (TYPE_MAIN_VARIANT (TREE_TYPE (expr)), - pddatype)) - return; - - /* The lower bound and element sizes must be constant. */ - if (!TYPE_SIZE_UNIT (ddatype) - || TREE_CODE (TYPE_SIZE_UNIT (ddatype)) != INTEGER_CST - || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype)) - || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST) - return; - - /* All checks succeeded. Build a new node to merge the cast. */ - *expr_p = build4 (ARRAY_REF, ddatype, TREE_OPERAND (addr_expr, 0), - TYPE_MIN_VALUE (TYPE_DOMAIN (datype)), - NULL_TREE, NULL_TREE); - *expr_p = build1 (ADDR_EXPR, pddatype, *expr_p); - - /* We can have stripped a required restrict qualifier above. */ - if (!useless_type_conversion_p (TREE_TYPE (expr), TREE_TYPE (*expr_p))) - *expr_p = fold_convert (TREE_TYPE (expr), *expr_p); -} - -/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions - underneath as appropriate. */ - -static enum gimplify_status -gimplify_conversion (tree *expr_p) -{ - location_t loc = EXPR_LOCATION (*expr_p); - gcc_assert (CONVERT_EXPR_P (*expr_p)); - - /* Then strip away all but the outermost conversion. */ - STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0)); - - /* And remove the outermost conversion if it's useless. */ - if (tree_ssa_useless_type_conversion (*expr_p)) - *expr_p = TREE_OPERAND (*expr_p, 0); - - /* If we still have a conversion at the toplevel, - then canonicalize some constructs. */ - if (CONVERT_EXPR_P (*expr_p)) - { - tree sub = TREE_OPERAND (*expr_p, 0); - - /* If a NOP conversion is changing the type of a COMPONENT_REF - expression, then canonicalize its type now in order to expose more - redundant conversions. */ - if (TREE_CODE (sub) == COMPONENT_REF) - canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0)); - - /* If a NOP conversion is changing a pointer to array of foo - to a pointer to foo, embed that change in the ADDR_EXPR. */ - else if (TREE_CODE (sub) == ADDR_EXPR) - canonicalize_addr_expr (expr_p); - } - - /* If we have a conversion to a non-register type force the - use of a VIEW_CONVERT_EXPR instead. */ - if (CONVERT_EXPR_P (*expr_p) && !is_gimple_reg_type (TREE_TYPE (*expr_p))) - *expr_p = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (*expr_p), - TREE_OPERAND (*expr_p, 0)); - - /* Canonicalize CONVERT_EXPR to NOP_EXPR. */ - if (TREE_CODE (*expr_p) == CONVERT_EXPR) - TREE_SET_CODE (*expr_p, NOP_EXPR); - - return GS_OK; -} - -/* Gimplify a VAR_DECL or PARM_DECL. Return GS_OK if we expanded a - DECL_VALUE_EXPR, and it's worth re-examining things. */ - -static enum gimplify_status -gimplify_var_or_parm_decl (tree *expr_p) -{ - tree decl = *expr_p; - - /* ??? If this is a local variable, and it has not been seen in any - outer BIND_EXPR, then it's probably the result of a duplicate - declaration, for which we've already issued an error. It would - be really nice if the front end wouldn't leak these at all. - Currently the only known culprit is C++ destructors, as seen - in g++.old-deja/g++.jason/binding.C. - Another possible culpit are size expressions for variably modified - types which are lost in the FE or not gimplified correctly. */ - if (VAR_P (decl) - && !DECL_SEEN_IN_BIND_EXPR_P (decl) - && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl) - && decl_function_context (decl) == current_function_decl) - { - gcc_assert (seen_error ()); - return GS_ERROR; - } - - /* When within an OMP context, notice uses of variables. */ - if (gimplify_omp_ctxp && omp_notice_variable (gimplify_omp_ctxp, decl, true)) - return GS_ALL_DONE; - - /* If the decl is an alias for another expression, substitute it now. */ - if (DECL_HAS_VALUE_EXPR_P (decl)) - { - *expr_p = unshare_expr (DECL_VALUE_EXPR (decl)); - return GS_OK; - } - - return GS_ALL_DONE; -} - -/* Recalculate the value of the TREE_SIDE_EFFECTS flag for T. */ - -static void -recalculate_side_effects (tree t) -{ - enum tree_code code = TREE_CODE (t); - int len = TREE_OPERAND_LENGTH (t); - int i; - - switch (TREE_CODE_CLASS (code)) - { - case tcc_expression: - switch (code) - { - case INIT_EXPR: - case MODIFY_EXPR: - case VA_ARG_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - /* All of these have side-effects, no matter what their - operands are. */ - return; - - default: - break; - } - /* Fall through. */ - - case tcc_comparison: /* a comparison expression */ - case tcc_unary: /* a unary arithmetic expression */ - case tcc_binary: /* a binary arithmetic expression */ - case tcc_reference: /* a reference */ - case tcc_vl_exp: /* a function call */ - TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); - for (i = 0; i < len; ++i) - { - tree op = TREE_OPERAND (t, i); - if (op && TREE_SIDE_EFFECTS (op)) - TREE_SIDE_EFFECTS (t) = 1; - } - break; - - case tcc_constant: - /* No side-effects. */ - return; - - default: - gcc_unreachable (); - } -} - -/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR - node *EXPR_P. - - compound_lval - : min_lval '[' val ']' - | min_lval '.' ID - | compound_lval '[' val ']' - | compound_lval '.' ID - - This is not part of the original SIMPLE definition, which separates - array and member references, but it seems reasonable to handle them - together. Also, this way we don't run into problems with union - aliasing; gcc requires that for accesses through a union to alias, the - union reference must be explicit, which was not always the case when we - were splitting up array and member refs. - - PRE_P points to the sequence where side effects that must happen before - *EXPR_P should be stored. - - POST_P points to the sequence where side effects that must happen after - *EXPR_P should be stored. */ - -static enum gimplify_status -gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - fallback_t fallback) -{ - tree *p; - enum gimplify_status ret = GS_ALL_DONE, tret; - int i; - location_t loc = EXPR_LOCATION (*expr_p); - tree expr = *expr_p; - - /* Create a stack of the subexpressions so later we can walk them in - order from inner to outer. */ - auto_vec<tree, 10> expr_stack; - - /* We can handle anything that get_inner_reference can deal with. */ - for (p = expr_p; ; p = &TREE_OPERAND (*p, 0)) - { - restart: - /* Fold INDIRECT_REFs now to turn them into ARRAY_REFs. */ - if (TREE_CODE (*p) == INDIRECT_REF) - *p = fold_indirect_ref_loc (loc, *p); - - if (handled_component_p (*p)) - ; - /* Expand DECL_VALUE_EXPR now. In some cases that may expose - additional COMPONENT_REFs. */ - else if ((VAR_P (*p) || TREE_CODE (*p) == PARM_DECL) - && gimplify_var_or_parm_decl (p) == GS_OK) - goto restart; - else - break; - - expr_stack.safe_push (*p); - } - - gcc_assert (expr_stack.length ()); - - /* Now EXPR_STACK is a stack of pointers to all the refs we've - walked through and P points to the innermost expression. - - Java requires that we elaborated nodes in source order. That - means we must gimplify the inner expression followed by each of - the indices, in order. But we can't gimplify the inner - expression until we deal with any variable bounds, sizes, or - positions in order to deal with PLACEHOLDER_EXPRs. - - The base expression may contain a statement expression that - has declarations used in size expressions, so has to be - gimplified before gimplifying the size expressions. - - So we do this in three steps. First we deal with variable - bounds, sizes, and positions, then we gimplify the base, - then we deal with the annotations for any variables in the - components and any indices, from left to right. */ - - for (i = expr_stack.length () - 1; i >= 0; i--) - { - tree t = expr_stack[i]; - - if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) - { - /* Deal with the low bound and element type size and put them into - the ARRAY_REF. If these values are set, they have already been - gimplified. */ - if (TREE_OPERAND (t, 2) == NULL_TREE) - { - tree low = unshare_expr (array_ref_low_bound (t)); - if (!is_gimple_min_invariant (low)) - { - TREE_OPERAND (t, 2) = low; - } - } - - if (TREE_OPERAND (t, 3) == NULL_TREE) - { - tree elmt_size = array_ref_element_size (t); - if (!is_gimple_min_invariant (elmt_size)) - { - elmt_size = unshare_expr (elmt_size); - tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0))); - tree factor = size_int (TYPE_ALIGN_UNIT (elmt_type)); - - /* Divide the element size by the alignment of the element - type (above). */ - elmt_size = size_binop_loc (loc, EXACT_DIV_EXPR, - elmt_size, factor); - - TREE_OPERAND (t, 3) = elmt_size; - } - } - } - else if (TREE_CODE (t) == COMPONENT_REF) - { - /* Set the field offset into T and gimplify it. */ - if (TREE_OPERAND (t, 2) == NULL_TREE) - { - tree offset = component_ref_field_offset (t); - if (!is_gimple_min_invariant (offset)) - { - offset = unshare_expr (offset); - tree field = TREE_OPERAND (t, 1); - tree factor - = size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT); - - /* Divide the offset by its alignment. */ - offset = size_binop_loc (loc, EXACT_DIV_EXPR, - offset, factor); - - TREE_OPERAND (t, 2) = offset; - } - } - } - } - - /* Step 2 is to gimplify the base expression. Make sure lvalue is set - so as to match the min_lval predicate. Failure to do so may result - in the creation of large aggregate temporaries. */ - tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, - fallback | fb_lvalue); - ret = MIN (ret, tret); - - /* Step 3: gimplify size expressions and the indices and operands of - ARRAY_REF. During this loop we also remove any useless conversions. */ - - for (; expr_stack.length () > 0; ) - { - tree t = expr_stack.pop (); - - if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) - { - /* Gimplify the low bound and element type size. */ - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - - tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - - /* Gimplify the dimension. */ - tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, - is_gimple_val, fb_rvalue); - ret = MIN (ret, tret); - } - else if (TREE_CODE (t) == COMPONENT_REF) - { - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - } - - STRIP_USELESS_TYPE_CONVERSION (TREE_OPERAND (t, 0)); - - /* The innermost expression P may have originally had - TREE_SIDE_EFFECTS set which would have caused all the outer - expressions in *EXPR_P leading to P to also have had - TREE_SIDE_EFFECTS set. */ - recalculate_side_effects (t); - } - - /* If the outermost expression is a COMPONENT_REF, canonicalize its type. */ - if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF) - { - canonicalize_component_ref (expr_p); - } - - expr_stack.release (); - - gcc_assert (*expr_p == expr || ret != GS_ALL_DONE); - - return ret; -} - -/* Gimplify the self modifying expression pointed to by EXPR_P - (++, --, +=, -=). - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. - - POST_P points to the list where side effects that must happen after - *EXPR_P should be stored. - - WANT_VALUE is nonzero iff we want to use the value of this expression - in another expression. - - ARITH_TYPE is the type the computation should be performed in. */ - -enum gimplify_status -gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool want_value, tree arith_type) -{ - enum tree_code code; - tree lhs, lvalue, rhs, t1; - gimple_seq post = NULL, *orig_post_p = post_p; - bool postfix; - enum tree_code arith_code; - enum gimplify_status ret; - location_t loc = EXPR_LOCATION (*expr_p); - - code = TREE_CODE (*expr_p); - - gcc_assert (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR - || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR); - - /* Prefix or postfix? */ - if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) - /* Faster to treat as prefix if result is not used. */ - postfix = want_value; - else - postfix = false; - - /* For postfix, make sure the inner expression's post side effects - are executed after side effects from this expression. */ - if (postfix) - post_p = &post; - - /* Add or subtract? */ - if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - arith_code = PLUS_EXPR; - else - arith_code = MINUS_EXPR; - - /* Gimplify the LHS into a GIMPLE lvalue. */ - lvalue = TREE_OPERAND (*expr_p, 0); - ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - if (ret == GS_ERROR) - return ret; - - /* Extract the operands to the arithmetic operation. */ - lhs = lvalue; - rhs = TREE_OPERAND (*expr_p, 1); - - /* For postfix operator, we evaluate the LHS to an rvalue and then use - that as the result value and in the postqueue operation. */ - if (postfix) - { - ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue); - if (ret == GS_ERROR) - return ret; - - lhs = get_initialized_tmp_var (lhs, pre_p); - } - - /* For POINTERs increment, use POINTER_PLUS_EXPR. */ - if (POINTER_TYPE_P (TREE_TYPE (lhs))) - { - rhs = convert_to_ptrofftype_loc (loc, rhs); - if (arith_code == MINUS_EXPR) - rhs = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (rhs), rhs); - t1 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs); - } - else - t1 = fold_convert (TREE_TYPE (*expr_p), - fold_build2 (arith_code, arith_type, - fold_convert (arith_type, lhs), - fold_convert (arith_type, rhs))); - - if (postfix) - { - gimplify_assign (lvalue, t1, pre_p); - gimplify_seq_add_seq (orig_post_p, post); - *expr_p = lhs; - return GS_ALL_DONE; - } - else - { - *expr_p = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1); - return GS_OK; - } -} - -/* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR. */ - -static void -maybe_with_size_expr (tree *expr_p) -{ - tree expr = *expr_p; - tree type = TREE_TYPE (expr); - tree size; - - /* If we've already wrapped this or the type is error_mark_node, we can't do - anything. */ - if (TREE_CODE (expr) == WITH_SIZE_EXPR - || type == error_mark_node) - return; - - /* If the size isn't known or is a constant, we have nothing to do. */ - size = TYPE_SIZE_UNIT (type); - if (!size || poly_int_tree_p (size)) - return; - - /* Otherwise, make a WITH_SIZE_EXPR. */ - size = unshare_expr (size); - size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, expr); - *expr_p = build2 (WITH_SIZE_EXPR, type, expr, size); -} - -/* Helper for gimplify_call_expr. Gimplify a single argument *ARG_P - Store any side-effects in PRE_P. CALL_LOCATION is the location of - the CALL_EXPR. If ALLOW_SSA is set the actual parameter may be - gimplified to an SSA name. */ - -enum gimplify_status -gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location, - bool allow_ssa) -{ - bool (*test) (tree); - fallback_t fb; - - /* In general, we allow lvalues for function arguments to avoid - extra overhead of copying large aggregates out of even larger - aggregates into temporaries only to copy the temporaries to - the argument list. Make optimizers happy by pulling out to - temporaries those types that fit in registers. */ - if (is_gimple_reg_type (TREE_TYPE (*arg_p))) - test = is_gimple_val, fb = fb_rvalue; - else - { - test = is_gimple_lvalue, fb = fb_either; - /* Also strip a TARGET_EXPR that would force an extra copy. */ - if (TREE_CODE (*arg_p) == TARGET_EXPR) - { - tree init = TARGET_EXPR_INITIAL (*arg_p); - if (init - && !VOID_TYPE_P (TREE_TYPE (init))) - *arg_p = init; - } - } - - /* If this is a variable sized type, we must remember the size. */ - maybe_with_size_expr (arg_p); - - /* FIXME diagnostics: This will mess up gcc.dg/Warray-bounds.c. */ - /* Make sure arguments have the same location as the function call - itself. */ - protected_set_expr_location (*arg_p, call_location); - - /* There is a sequence point before a function call. Side effects in - the argument list must occur before the actual call. So, when - gimplifying arguments, force gimplify_expr to use an internal - post queue which is then appended to the end of PRE_P. */ - return gimplify_expr (arg_p, pre_p, NULL, test, fb, allow_ssa); -} - -/* Don't fold inside offloading or taskreg regions: it can break code by - adding decl references that weren't in the source. We'll do it during - omplower pass instead. */ - -static bool -maybe_fold_stmt (gimple_stmt_iterator *gsi) -{ - struct gimplify_omp_ctx *ctx; - for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context) - if ((ctx->region_type & (ORT_TARGET | ORT_PARALLEL | ORT_TASK)) != 0) - return false; - else if ((ctx->region_type & ORT_HOST_TEAMS) == ORT_HOST_TEAMS) - return false; - /* Delay folding of builtins until the IL is in consistent state - so the diagnostic machinery can do a better job. */ - if (gimple_call_builtin_p (gsi_stmt (*gsi))) - return false; - return fold_stmt (gsi); -} - -/* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P. - WANT_VALUE is true if the result of the call is desired. */ - -static enum gimplify_status -gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) -{ - tree fndecl, parms, p, fnptrtype; - enum gimplify_status ret; - int i, nargs; - gcall *call; - bool builtin_va_start_p = false; - location_t loc = EXPR_LOCATION (*expr_p); - - gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR); - - /* For reliable diagnostics during inlining, it is necessary that - every call_expr be annotated with file and line. */ - if (! EXPR_HAS_LOCATION (*expr_p)) - SET_EXPR_LOCATION (*expr_p, input_location); - - /* Gimplify internal functions created in the FEs. */ - if (CALL_EXPR_FN (*expr_p) == NULL_TREE) - { - if (want_value) - return GS_ALL_DONE; - - nargs = call_expr_nargs (*expr_p); - enum internal_fn ifn = CALL_EXPR_IFN (*expr_p); - auto_vec<tree> vargs (nargs); - - for (i = 0; i < nargs; i++) - { - gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, - EXPR_LOCATION (*expr_p)); - vargs.quick_push (CALL_EXPR_ARG (*expr_p, i)); - } - - gcall *call = gimple_build_call_internal_vec (ifn, vargs); - gimple_call_set_nothrow (call, TREE_NOTHROW (*expr_p)); - gimplify_seq_add_stmt (pre_p, call); - return GS_ALL_DONE; - } - - /* This may be a call to a builtin function. - - Builtin function calls may be transformed into different - (and more efficient) builtin function calls under certain - circumstances. Unfortunately, gimplification can muck things - up enough that the builtin expanders are not aware that certain - transformations are still valid. - - So we attempt transformation/gimplification of the call before - we gimplify the CALL_EXPR. At this time we do not manage to - transform all calls in the same manner as the expanders do, but - we do transform most of them. */ - fndecl = get_callee_fndecl (*expr_p); - if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_BUILT_IN_ALLOCA: - /* If the call has been built for a variable-sized object, then we - want to restore the stack level when the enclosing BIND_EXPR is - exited to reclaim the allocated space; otherwise, we precisely - need to do the opposite and preserve the latest stack level. */ - if (CALL_ALLOCA_FOR_VAR_P (*expr_p)) - gimplify_ctxp->save_stack = true; - else - gimplify_ctxp->keep_stack = true; - break; - - case BUILT_IN_VA_START: - { - builtin_va_start_p = TRUE; - if (call_expr_nargs (*expr_p) < 2) - { - error ("too few arguments to function %<va_start%>"); - *expr_p = build_empty_stmt (EXPR_LOCATION (*expr_p)); - return GS_OK; - } - - if (fold_builtin_next_arg (*expr_p, true)) - { - *expr_p = build_empty_stmt (EXPR_LOCATION (*expr_p)); - return GS_OK; - } - break; - } - - case BUILT_IN_EH_RETURN: - cfun->calls_eh_return = true; - break; - - case BUILT_IN_CLEAR_PADDING: - if (call_expr_nargs (*expr_p) == 1) - { - /* Remember the original type of the argument in an internal - dummy second argument, as in GIMPLE pointer conversions are - useless. also mark this call as not for automatic initialization - in the internal dummy third argument. */ - p = CALL_EXPR_ARG (*expr_p, 0); - bool for_auto_init = false; - *expr_p - = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 3, p, - build_zero_cst (TREE_TYPE (p)), - build_int_cst (integer_type_node, - (int) for_auto_init)); - return GS_OK; - } - break; - - default: - ; - } - if (fndecl && fndecl_built_in_p (fndecl)) - { - tree new_tree = fold_call_expr (input_location, *expr_p, !want_value); - if (new_tree && new_tree != *expr_p) - { - /* There was a transformation of this call which computes the - same value, but in a more efficient way. Return and try - again. */ - *expr_p = new_tree; - return GS_OK; - } - } - - /* Remember the original function pointer type. */ - fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p)); - - if (flag_openmp - && fndecl - && cfun - && (cfun->curr_properties & PROP_gimple_any) == 0) - { - tree variant = omp_resolve_declare_variant (fndecl); - if (variant != fndecl) - CALL_EXPR_FN (*expr_p) = build1 (ADDR_EXPR, fnptrtype, variant); - } - - /* There is a sequence point before the call, so any side effects in - the calling expression must occur before the actual call. Force - gimplify_expr to use an internal post queue. */ - ret = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL, - is_gimple_call_addr, fb_rvalue); - - nargs = call_expr_nargs (*expr_p); - - /* Get argument types for verification. */ - fndecl = get_callee_fndecl (*expr_p); - parms = NULL_TREE; - if (fndecl) - parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - else - parms = TYPE_ARG_TYPES (TREE_TYPE (fnptrtype)); - - if (fndecl && DECL_ARGUMENTS (fndecl)) - p = DECL_ARGUMENTS (fndecl); - else if (parms) - p = parms; - else - p = NULL_TREE; - for (i = 0; i < nargs && p; i++, p = TREE_CHAIN (p)) - ; - - /* If the last argument is __builtin_va_arg_pack () and it is not - passed as a named argument, decrease the number of CALL_EXPR - arguments and set instead the CALL_EXPR_VA_ARG_PACK flag. */ - if (!p - && i < nargs - && TREE_CODE (CALL_EXPR_ARG (*expr_p, nargs - 1)) == CALL_EXPR) - { - tree last_arg = CALL_EXPR_ARG (*expr_p, nargs - 1); - tree last_arg_fndecl = get_callee_fndecl (last_arg); - - if (last_arg_fndecl - && fndecl_built_in_p (last_arg_fndecl, BUILT_IN_VA_ARG_PACK)) - { - tree call = *expr_p; - - --nargs; - *expr_p = build_call_array_loc (loc, TREE_TYPE (call), - CALL_EXPR_FN (call), - nargs, CALL_EXPR_ARGP (call)); - - /* Copy all CALL_EXPR flags, location and block, except - CALL_EXPR_VA_ARG_PACK flag. */ - CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call); - CALL_EXPR_TAILCALL (*expr_p) = CALL_EXPR_TAILCALL (call); - CALL_EXPR_RETURN_SLOT_OPT (*expr_p) - = CALL_EXPR_RETURN_SLOT_OPT (call); - CALL_FROM_THUNK_P (*expr_p) = CALL_FROM_THUNK_P (call); - SET_EXPR_LOCATION (*expr_p, EXPR_LOCATION (call)); - - /* Set CALL_EXPR_VA_ARG_PACK. */ - CALL_EXPR_VA_ARG_PACK (*expr_p) = 1; - } - } - - /* If the call returns twice then after building the CFG the call - argument computations will no longer dominate the call because - we add an abnormal incoming edge to the call. So do not use SSA - vars there. */ - bool returns_twice = call_expr_flags (*expr_p) & ECF_RETURNS_TWICE; - - /* Gimplify the function arguments. */ - if (nargs > 0) - { - for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0); - PUSH_ARGS_REVERSED ? i >= 0 : i < nargs; - PUSH_ARGS_REVERSED ? i-- : i++) - { - enum gimplify_status t; - - /* Avoid gimplifying the second argument to va_start, which needs to - be the plain PARM_DECL. */ - if ((i != 1) || !builtin_va_start_p) - { - t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, - EXPR_LOCATION (*expr_p), ! returns_twice); - - if (t == GS_ERROR) - ret = GS_ERROR; - } - } - } - - /* Gimplify the static chain. */ - if (CALL_EXPR_STATIC_CHAIN (*expr_p)) - { - if (fndecl && !DECL_STATIC_CHAIN (fndecl)) - CALL_EXPR_STATIC_CHAIN (*expr_p) = NULL; - else - { - enum gimplify_status t; - t = gimplify_arg (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, - EXPR_LOCATION (*expr_p), ! returns_twice); - if (t == GS_ERROR) - ret = GS_ERROR; - } - } - - /* Verify the function result. */ - if (want_value && fndecl - && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fnptrtype)))) - { - error_at (loc, "using result of function returning %<void%>"); - ret = GS_ERROR; - } - - /* Try this again in case gimplification exposed something. */ - if (ret != GS_ERROR) - { - tree new_tree = fold_call_expr (input_location, *expr_p, !want_value); - - if (new_tree && new_tree != *expr_p) - { - /* There was a transformation of this call which computes the - same value, but in a more efficient way. Return and try - again. */ - *expr_p = new_tree; - return GS_OK; - } - } - else - { - *expr_p = error_mark_node; - return GS_ERROR; - } - - /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its - decl. This allows us to eliminate redundant or useless - calls to "const" functions. */ - if (TREE_CODE (*expr_p) == CALL_EXPR) - { - int flags = call_expr_flags (*expr_p); - if (flags & (ECF_CONST | ECF_PURE) - /* An infinite loop is considered a side effect. */ - && !(flags & (ECF_LOOPING_CONST_OR_PURE))) - TREE_SIDE_EFFECTS (*expr_p) = 0; - } - - /* If the value is not needed by the caller, emit a new GIMPLE_CALL - and clear *EXPR_P. Otherwise, leave *EXPR_P in its gimplified - form and delegate the creation of a GIMPLE_CALL to - gimplify_modify_expr. This is always possible because when - WANT_VALUE is true, the caller wants the result of this call into - a temporary, which means that we will emit an INIT_EXPR in - internal_get_tmp_var which will then be handled by - gimplify_modify_expr. */ - if (!want_value) - { - /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we - have to do is replicate it as a GIMPLE_CALL tuple. */ - gimple_stmt_iterator gsi; - call = gimple_build_call_from_tree (*expr_p, fnptrtype); - notice_special_calls (call); - gimplify_seq_add_stmt (pre_p, call); - gsi = gsi_last (*pre_p); - maybe_fold_stmt (&gsi); - *expr_p = NULL_TREE; - } - else - /* Remember the original function type. */ - CALL_EXPR_FN (*expr_p) = build1 (NOP_EXPR, fnptrtype, - CALL_EXPR_FN (*expr_p)); - - return ret; -} - -/* Handle shortcut semantics in the predicate operand of a COND_EXPR by - rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs. - - TRUE_LABEL_P and FALSE_LABEL_P point to the labels to jump to if the - condition is true or false, respectively. If null, we should generate - our own to skip over the evaluation of this specific expression. - - LOCUS is the source location of the COND_EXPR. - - This function is the tree equivalent of do_jump. - - shortcut_cond_r should only be called by shortcut_cond_expr. */ - -static tree -shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, - location_t locus) -{ - tree local_label = NULL_TREE; - tree t, expr = NULL; - - /* OK, it's not a simple case; we need to pull apart the COND_EXPR to - retain the shortcut semantics. Just insert the gotos here; - shortcut_cond_expr will append the real blocks later. */ - if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) - { - location_t new_locus; - - /* Turn if (a && b) into - - if (a); else goto no; - if (b) goto yes; else goto no; - (no:) */ - - if (false_label_p == NULL) - false_label_p = &local_label; - - /* Keep the original source location on the first 'if'. */ - t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p, locus); - append_to_statement_list (t, &expr); - - /* Set the source location of the && on the second 'if'. */ - new_locus = rexpr_location (pred, locus); - t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, - new_locus); - append_to_statement_list (t, &expr); - } - else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR) - { - location_t new_locus; - - /* Turn if (a || b) into - - if (a) goto yes; - if (b) goto yes; else goto no; - (yes:) */ - - if (true_label_p == NULL) - true_label_p = &local_label; - - /* Keep the original source location on the first 'if'. */ - t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL, locus); - append_to_statement_list (t, &expr); - - /* Set the source location of the || on the second 'if'. */ - new_locus = rexpr_location (pred, locus); - t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, - new_locus); - append_to_statement_list (t, &expr); - } - else if (TREE_CODE (pred) == COND_EXPR - && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 1))) - && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 2)))) - { - location_t new_locus; - - /* As long as we're messing with gotos, turn if (a ? b : c) into - if (a) - if (b) goto yes; else goto no; - else - if (c) goto yes; else goto no; - - Don't do this if one of the arms has void type, which can happen - in C++ when the arm is throw. */ - - /* Keep the original source location on the first 'if'. Set the source - location of the ? on the second 'if'. */ - new_locus = rexpr_location (pred, locus); - expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0), - shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, - false_label_p, locus), - shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p, - false_label_p, new_locus)); - } - else - { - expr = build3 (COND_EXPR, void_type_node, pred, - build_and_jump (true_label_p), - build_and_jump (false_label_p)); - SET_EXPR_LOCATION (expr, locus); - } - - if (local_label) - { - t = build1 (LABEL_EXPR, void_type_node, local_label); - append_to_statement_list (t, &expr); - } - - return expr; -} - -/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip - any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent - statement, if it is the last one. Otherwise, return NULL. */ - -static tree -find_goto (tree expr) -{ - if (!expr) - return NULL_TREE; - - if (TREE_CODE (expr) == GOTO_EXPR) - return expr; - - if (TREE_CODE (expr) != STATEMENT_LIST) - return NULL_TREE; - - tree_stmt_iterator i = tsi_start (expr); - - while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) - tsi_next (&i); - - if (!tsi_one_before_end_p (i)) - return NULL_TREE; - - return find_goto (tsi_stmt (i)); -} - -/* Same as find_goto, except that it returns NULL if the destination - is not a LABEL_DECL. */ - -static inline tree -find_goto_label (tree expr) -{ - tree dest = find_goto (expr); - if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL) - return dest; - return NULL_TREE; -} - -/* Given a conditional expression EXPR with short-circuit boolean - predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the - predicate apart into the equivalent sequence of conditionals. */ - -static tree -shortcut_cond_expr (tree expr) -{ - tree pred = TREE_OPERAND (expr, 0); - tree then_ = TREE_OPERAND (expr, 1); - tree else_ = TREE_OPERAND (expr, 2); - tree true_label, false_label, end_label, t; - tree *true_label_p; - tree *false_label_p; - bool emit_end, emit_false, jump_over_else; - bool then_se = then_ && TREE_SIDE_EFFECTS (then_); - bool else_se = else_ && TREE_SIDE_EFFECTS (else_); - - /* First do simple transformations. */ - if (!else_se) - { - /* If there is no 'else', turn - if (a && b) then c - into - if (a) if (b) then c. */ - while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) - { - /* Keep the original source location on the first 'if'. */ - location_t locus = EXPR_LOC_OR_LOC (expr, input_location); - TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); - /* Set the source location of the && on the second 'if'. */ - if (rexpr_has_location (pred)) - SET_EXPR_LOCATION (expr, rexpr_location (pred)); - then_ = shortcut_cond_expr (expr); - then_se = then_ && TREE_SIDE_EFFECTS (then_); - pred = TREE_OPERAND (pred, 0); - expr = build3 (COND_EXPR, void_type_node, pred, then_, NULL_TREE); - SET_EXPR_LOCATION (expr, locus); - } - } - - if (!then_se) - { - /* If there is no 'then', turn - if (a || b); else d - into - if (a); else if (b); else d. */ - while (TREE_CODE (pred) == TRUTH_ORIF_EXPR) - { - /* Keep the original source location on the first 'if'. */ - location_t locus = EXPR_LOC_OR_LOC (expr, input_location); - TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); - /* Set the source location of the || on the second 'if'. */ - if (rexpr_has_location (pred)) - SET_EXPR_LOCATION (expr, rexpr_location (pred)); - else_ = shortcut_cond_expr (expr); - else_se = else_ && TREE_SIDE_EFFECTS (else_); - pred = TREE_OPERAND (pred, 0); - expr = build3 (COND_EXPR, void_type_node, pred, NULL_TREE, else_); - SET_EXPR_LOCATION (expr, locus); - } - } - - /* If we're done, great. */ - if (TREE_CODE (pred) != TRUTH_ANDIF_EXPR - && TREE_CODE (pred) != TRUTH_ORIF_EXPR) - return expr; - - /* Otherwise we need to mess with gotos. Change - if (a) c; else d; - to - if (a); else goto no; - c; goto end; - no: d; end: - and recursively gimplify the condition. */ - - true_label = false_label = end_label = NULL_TREE; - - /* If our arms just jump somewhere, hijack those labels so we don't - generate jumps to jumps. */ - - if (tree then_goto = find_goto_label (then_)) - { - true_label = GOTO_DESTINATION (then_goto); - then_ = NULL; - then_se = false; - } - - if (tree else_goto = find_goto_label (else_)) - { - false_label = GOTO_DESTINATION (else_goto); - else_ = NULL; - else_se = false; - } - - /* If we aren't hijacking a label for the 'then' branch, it falls through. */ - if (true_label) - true_label_p = &true_label; - else - true_label_p = NULL; - - /* The 'else' branch also needs a label if it contains interesting code. */ - if (false_label || else_se) - false_label_p = &false_label; - else - false_label_p = NULL; - - /* If there was nothing else in our arms, just forward the label(s). */ - if (!then_se && !else_se) - return shortcut_cond_r (pred, true_label_p, false_label_p, - EXPR_LOC_OR_LOC (expr, input_location)); - - /* If our last subexpression already has a terminal label, reuse it. */ - if (else_se) - t = expr_last (else_); - else if (then_se) - t = expr_last (then_); - else - t = NULL; - if (t && TREE_CODE (t) == LABEL_EXPR) - end_label = LABEL_EXPR_LABEL (t); - - /* If we don't care about jumping to the 'else' branch, jump to the end - if the condition is false. */ - if (!false_label_p) - false_label_p = &end_label; - - /* We only want to emit these labels if we aren't hijacking them. */ - emit_end = (end_label == NULL_TREE); - emit_false = (false_label == NULL_TREE); - - /* We only emit the jump over the else clause if we have to--if the - then clause may fall through. Otherwise we can wind up with a - useless jump and a useless label at the end of gimplified code, - which will cause us to think that this conditional as a whole - falls through even if it doesn't. If we then inline a function - which ends with such a condition, that can cause us to issue an - inappropriate warning about control reaching the end of a - non-void function. */ - jump_over_else = block_may_fallthru (then_); - - pred = shortcut_cond_r (pred, true_label_p, false_label_p, - EXPR_LOC_OR_LOC (expr, input_location)); - - expr = NULL; - append_to_statement_list (pred, &expr); - - append_to_statement_list (then_, &expr); - if (else_se) - { - if (jump_over_else) - { - tree last = expr_last (expr); - t = build_and_jump (&end_label); - if (rexpr_has_location (last)) - SET_EXPR_LOCATION (t, rexpr_location (last)); - append_to_statement_list (t, &expr); - } - if (emit_false) - { - t = build1 (LABEL_EXPR, void_type_node, false_label); - append_to_statement_list (t, &expr); - } - append_to_statement_list (else_, &expr); - } - if (emit_end && end_label) - { - t = build1 (LABEL_EXPR, void_type_node, end_label); - append_to_statement_list (t, &expr); - } - - return expr; -} - -/* EXPR is used in a boolean context; make sure it has BOOLEAN_TYPE. */ - -tree -gimple_boolify (tree expr) -{ - tree type = TREE_TYPE (expr); - location_t loc = EXPR_LOCATION (expr); - - if (TREE_CODE (expr) == NE_EXPR - && TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR - && integer_zerop (TREE_OPERAND (expr, 1))) - { - tree call = TREE_OPERAND (expr, 0); - tree fn = get_callee_fndecl (call); - - /* For __builtin_expect ((long) (x), y) recurse into x as well - if x is truth_value_p. */ - if (fn - && fndecl_built_in_p (fn, BUILT_IN_EXPECT) - && call_expr_nargs (call) == 2) - { - tree arg = CALL_EXPR_ARG (call, 0); - if (arg) - { - if (TREE_CODE (arg) == NOP_EXPR - && TREE_TYPE (arg) == TREE_TYPE (call)) - arg = TREE_OPERAND (arg, 0); - if (truth_value_p (TREE_CODE (arg))) - { - arg = gimple_boolify (arg); - CALL_EXPR_ARG (call, 0) - = fold_convert_loc (loc, TREE_TYPE (call), arg); - } - } - } - } - - switch (TREE_CODE (expr)) - { - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - /* Also boolify the arguments of truth exprs. */ - TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1)); - /* FALLTHRU */ - - case TRUTH_NOT_EXPR: - TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); - - /* These expressions always produce boolean results. */ - if (TREE_CODE (type) != BOOLEAN_TYPE) - TREE_TYPE (expr) = boolean_type_node; - return expr; - - case ANNOTATE_EXPR: - switch ((enum annot_expr_kind) TREE_INT_CST_LOW (TREE_OPERAND (expr, 1))) - { - case annot_expr_ivdep_kind: - case annot_expr_unroll_kind: - case annot_expr_no_vector_kind: - case annot_expr_vector_kind: - case annot_expr_parallel_kind: - TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); - if (TREE_CODE (type) != BOOLEAN_TYPE) - TREE_TYPE (expr) = boolean_type_node; - return expr; - default: - gcc_unreachable (); - } - - default: - if (COMPARISON_CLASS_P (expr)) - { - /* There expressions always prduce boolean results. */ - if (TREE_CODE (type) != BOOLEAN_TYPE) - TREE_TYPE (expr) = boolean_type_node; - return expr; - } - /* Other expressions that get here must have boolean values, but - might need to be converted to the appropriate mode. */ - if (TREE_CODE (type) == BOOLEAN_TYPE) - return expr; - return fold_convert_loc (loc, boolean_type_node, expr); - } -} - -/* Given a conditional expression *EXPR_P without side effects, gimplify - its operands. New statements are inserted to PRE_P. */ - -static enum gimplify_status -gimplify_pure_cond_expr (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p, cond; - enum gimplify_status ret, tret; - enum tree_code code; - - cond = gimple_boolify (COND_EXPR_COND (expr)); - - /* We need to handle && and || specially, as their gimplification - creates pure cond_expr, thus leading to an infinite cycle otherwise. */ - code = TREE_CODE (cond); - if (code == TRUTH_ANDIF_EXPR) - TREE_SET_CODE (cond, TRUTH_AND_EXPR); - else if (code == TRUTH_ORIF_EXPR) - TREE_SET_CODE (cond, TRUTH_OR_EXPR); - ret = gimplify_expr (&cond, pre_p, NULL, is_gimple_condexpr, fb_rvalue); - COND_EXPR_COND (*expr_p) = cond; - - tret = gimplify_expr (&COND_EXPR_THEN (expr), pre_p, NULL, - is_gimple_val, fb_rvalue); - ret = MIN (ret, tret); - tret = gimplify_expr (&COND_EXPR_ELSE (expr), pre_p, NULL, - is_gimple_val, fb_rvalue); - - return MIN (ret, tret); -} - -/* Return true if evaluating EXPR could trap. - EXPR is GENERIC, while tree_could_trap_p can be called - only on GIMPLE. */ - -bool -generic_expr_could_trap_p (tree expr) -{ - unsigned i, n; - - if (!expr || is_gimple_val (expr)) - return false; - - if (!EXPR_P (expr) || tree_could_trap_p (expr)) - return true; - - n = TREE_OPERAND_LENGTH (expr); - for (i = 0; i < n; i++) - if (generic_expr_could_trap_p (TREE_OPERAND (expr, i))) - return true; - - return false; -} - -/* Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;' - into - - if (p) if (p) - t1 = a; a; - else or else - t1 = b; b; - t1; - - The second form is used when *EXPR_P is of type void. - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. */ - -static enum gimplify_status -gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) -{ - tree expr = *expr_p; - tree type = TREE_TYPE (expr); - location_t loc = EXPR_LOCATION (expr); - tree tmp, arm1, arm2; - enum gimplify_status ret; - tree label_true, label_false, label_cont; - bool have_then_clause_p, have_else_clause_p; - gcond *cond_stmt; - enum tree_code pred_code; - gimple_seq seq = NULL; - - /* If this COND_EXPR has a value, copy the values into a temporary within - the arms. */ - if (!VOID_TYPE_P (type)) - { - tree then_ = TREE_OPERAND (expr, 1), else_ = TREE_OPERAND (expr, 2); - tree result; - - /* If either an rvalue is ok or we do not require an lvalue, create the - temporary. But we cannot do that if the type is addressable. */ - if (((fallback & fb_rvalue) || !(fallback & fb_lvalue)) - && !TREE_ADDRESSABLE (type)) - { - if (gimplify_ctxp->allow_rhs_cond_expr - /* If either branch has side effects or could trap, it can't be - evaluated unconditionally. */ - && !TREE_SIDE_EFFECTS (then_) - && !generic_expr_could_trap_p (then_) - && !TREE_SIDE_EFFECTS (else_) - && !generic_expr_could_trap_p (else_)) - return gimplify_pure_cond_expr (expr_p, pre_p); - - tmp = create_tmp_var (type, "iftmp"); - result = tmp; - } - - /* Otherwise, only create and copy references to the values. */ - else - { - type = build_pointer_type (type); - - if (!VOID_TYPE_P (TREE_TYPE (then_))) - then_ = build_fold_addr_expr_loc (loc, then_); - - if (!VOID_TYPE_P (TREE_TYPE (else_))) - else_ = build_fold_addr_expr_loc (loc, else_); - - expr - = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_); - - tmp = create_tmp_var (type, "iftmp"); - result = build_simple_mem_ref_loc (loc, tmp); - } - - /* Build the new then clause, `tmp = then_;'. But don't build the - assignment if the value is void; in C++ it can be if it's a throw. */ - if (!VOID_TYPE_P (TREE_TYPE (then_))) - TREE_OPERAND (expr, 1) = build2 (INIT_EXPR, type, tmp, then_); - - /* Similarly, build the new else clause, `tmp = else_;'. */ - if (!VOID_TYPE_P (TREE_TYPE (else_))) - TREE_OPERAND (expr, 2) = build2 (INIT_EXPR, type, tmp, else_); - - TREE_TYPE (expr) = void_type_node; - recalculate_side_effects (expr); - - /* Move the COND_EXPR to the prequeue. */ - gimplify_stmt (&expr, pre_p); - - *expr_p = result; - return GS_ALL_DONE; - } - - /* Remove any COMPOUND_EXPR so the following cases will be caught. */ - STRIP_TYPE_NOPS (TREE_OPERAND (expr, 0)); - if (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPOUND_EXPR) - gimplify_compound_expr (&TREE_OPERAND (expr, 0), pre_p, true); - - /* Make sure the condition has BOOLEAN_TYPE. */ - TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); - - /* Break apart && and || conditions. */ - if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR - || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR) - { - expr = shortcut_cond_expr (expr); - - if (expr != *expr_p) - { - *expr_p = expr; - - /* We can't rely on gimplify_expr to re-gimplify the expanded - form properly, as cleanups might cause the target labels to be - wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to - set up a conditional context. */ - gimple_push_condition (); - gimplify_stmt (expr_p, &seq); - gimple_pop_condition (pre_p); - gimple_seq_add_seq (pre_p, seq); - - return GS_ALL_DONE; - } - } - - /* Now do the normal gimplification. */ - - /* Gimplify condition. */ - ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, - is_gimple_condexpr_for_cond, fb_rvalue); - if (ret == GS_ERROR) - return GS_ERROR; - gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE); - - gimple_push_condition (); - - have_then_clause_p = have_else_clause_p = false; - label_true = find_goto_label (TREE_OPERAND (expr, 1)); - if (label_true - && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl - /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR - have different locations, otherwise we end up with incorrect - location information on the branches. */ - && (optimize - || !EXPR_HAS_LOCATION (expr) - || !rexpr_has_location (label_true) - || EXPR_LOCATION (expr) == rexpr_location (label_true))) - { - have_then_clause_p = true; - label_true = GOTO_DESTINATION (label_true); - } - else - label_true = create_artificial_label (UNKNOWN_LOCATION); - label_false = find_goto_label (TREE_OPERAND (expr, 2)); - if (label_false - && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl - /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR - have different locations, otherwise we end up with incorrect - location information on the branches. */ - && (optimize - || !EXPR_HAS_LOCATION (expr) - || !rexpr_has_location (label_false) - || EXPR_LOCATION (expr) == rexpr_location (label_false))) - { - have_else_clause_p = true; - label_false = GOTO_DESTINATION (label_false); - } - else - label_false = create_artificial_label (UNKNOWN_LOCATION); - - gimple_cond_get_ops_from_tree (COND_EXPR_COND (expr), &pred_code, &arm1, - &arm2); - cond_stmt = gimple_build_cond (pred_code, arm1, arm2, label_true, - label_false); - gimple_set_location (cond_stmt, EXPR_LOCATION (expr)); - copy_warning (cond_stmt, COND_EXPR_COND (expr)); - gimplify_seq_add_stmt (&seq, cond_stmt); - gimple_stmt_iterator gsi = gsi_last (seq); - maybe_fold_stmt (&gsi); - - label_cont = NULL_TREE; - if (!have_then_clause_p) - { - /* For if (...) {} else { code; } put label_true after - the else block. */ - if (TREE_OPERAND (expr, 1) == NULL_TREE - && !have_else_clause_p - && TREE_OPERAND (expr, 2) != NULL_TREE) - label_cont = label_true; - else - { - gimplify_seq_add_stmt (&seq, gimple_build_label (label_true)); - have_then_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 1), &seq); - /* For if (...) { code; } else {} or - if (...) { code; } else goto label; or - if (...) { code; return; } else { ... } - label_cont isn't needed. */ - if (!have_else_clause_p - && TREE_OPERAND (expr, 2) != NULL_TREE - && gimple_seq_may_fallthru (seq)) - { - gimple *g; - label_cont = create_artificial_label (UNKNOWN_LOCATION); - - g = gimple_build_goto (label_cont); - - /* GIMPLE_COND's are very low level; they have embedded - gotos. This particular embedded goto should not be marked - with the location of the original COND_EXPR, as it would - correspond to the COND_EXPR's condition, not the ELSE or the - THEN arms. To avoid marking it with the wrong location, flag - it as "no location". */ - gimple_set_do_not_emit_location (g); - - gimplify_seq_add_stmt (&seq, g); - } - } - } - if (!have_else_clause_p) - { - gimplify_seq_add_stmt (&seq, gimple_build_label (label_false)); - have_else_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 2), &seq); - } - if (label_cont) - gimplify_seq_add_stmt (&seq, gimple_build_label (label_cont)); - - gimple_pop_condition (pre_p); - gimple_seq_add_seq (pre_p, seq); - - if (ret == GS_ERROR) - ; /* Do nothing. */ - else if (have_then_clause_p || have_else_clause_p) - ret = GS_ALL_DONE; - else - { - /* Both arms are empty; replace the COND_EXPR with its predicate. */ - expr = TREE_OPERAND (expr, 0); - gimplify_stmt (&expr, pre_p); - } - - *expr_p = NULL; - return ret; -} - -/* Prepare the node pointed to by EXPR_P, an is_gimple_addressable expression, - to be marked addressable. - - We cannot rely on such an expression being directly markable if a temporary - has been created by the gimplification. In this case, we create another - temporary and initialize it with a copy, which will become a store after we - mark it addressable. This can happen if the front-end passed us something - that it could not mark addressable yet, like a Fortran pass-by-reference - parameter (int) floatvar. */ - -static void -prepare_gimple_addressable (tree *expr_p, gimple_seq *seq_p) -{ - while (handled_component_p (*expr_p)) - expr_p = &TREE_OPERAND (*expr_p, 0); - if (is_gimple_reg (*expr_p)) - { - /* Do not allow an SSA name as the temporary. */ - tree var = get_initialized_tmp_var (*expr_p, seq_p, NULL, false); - DECL_NOT_GIMPLE_REG_P (var) = 1; - *expr_p = var; - } -} - -/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with - a call to __builtin_memcpy. */ - -static enum gimplify_status -gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value, - gimple_seq *seq_p) -{ - tree t, to, to_ptr, from, from_ptr; - gcall *gs; - location_t loc = EXPR_LOCATION (*expr_p); - - to = TREE_OPERAND (*expr_p, 0); - from = TREE_OPERAND (*expr_p, 1); - - /* Mark the RHS addressable. Beware that it may not be possible to do so - directly if a temporary has been created by the gimplification. */ - prepare_gimple_addressable (&from, seq_p); - - mark_addressable (from); - from_ptr = build_fold_addr_expr_loc (loc, from); - gimplify_arg (&from_ptr, seq_p, loc); - - mark_addressable (to); - to_ptr = build_fold_addr_expr_loc (loc, to); - gimplify_arg (&to_ptr, seq_p, loc); - - t = builtin_decl_implicit (BUILT_IN_MEMCPY); - - gs = gimple_build_call (t, 3, to_ptr, from_ptr, size); - gimple_call_set_alloca_for_var (gs, true); - - if (want_value) - { - /* tmp = memcpy() */ - t = create_tmp_var (TREE_TYPE (to_ptr)); - gimple_call_set_lhs (gs, t); - gimplify_seq_add_stmt (seq_p, gs); - - *expr_p = build_simple_mem_ref (t); - return GS_ALL_DONE; - } - - gimplify_seq_add_stmt (seq_p, gs); - *expr_p = NULL; - return GS_ALL_DONE; -} - -/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with - a call to __builtin_memset. In this case we know that the RHS is - a CONSTRUCTOR with an empty element list. */ - -static enum gimplify_status -gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value, - gimple_seq *seq_p) -{ - tree t, from, to, to_ptr; - gcall *gs; - location_t loc = EXPR_LOCATION (*expr_p); - - /* Assert our assumptions, to abort instead of producing wrong code - silently if they are not met. Beware that the RHS CONSTRUCTOR might - not be immediately exposed. */ - from = TREE_OPERAND (*expr_p, 1); - if (TREE_CODE (from) == WITH_SIZE_EXPR) - from = TREE_OPERAND (from, 0); - - gcc_assert (TREE_CODE (from) == CONSTRUCTOR - && vec_safe_is_empty (CONSTRUCTOR_ELTS (from))); - - /* Now proceed. */ - to = TREE_OPERAND (*expr_p, 0); - - to_ptr = build_fold_addr_expr_loc (loc, to); - gimplify_arg (&to_ptr, seq_p, loc); - t = builtin_decl_implicit (BUILT_IN_MEMSET); - - gs = gimple_build_call (t, 3, to_ptr, integer_zero_node, size); - - if (want_value) - { - /* tmp = memset() */ - t = create_tmp_var (TREE_TYPE (to_ptr)); - gimple_call_set_lhs (gs, t); - gimplify_seq_add_stmt (seq_p, gs); - - *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t); - return GS_ALL_DONE; - } - - gimplify_seq_add_stmt (seq_p, gs); - *expr_p = NULL; - return GS_ALL_DONE; -} - -/* A subroutine of gimplify_init_ctor_preeval. Called via walk_tree, - determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an - assignment. Return non-null if we detect a potential overlap. */ - -struct gimplify_init_ctor_preeval_data -{ - /* The base decl of the lhs object. May be NULL, in which case we - have to assume the lhs is indirect. */ - tree lhs_base_decl; - - /* The alias set of the lhs object. */ - alias_set_type lhs_alias_set; -}; - -static tree -gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata) -{ - struct gimplify_init_ctor_preeval_data *data - = (struct gimplify_init_ctor_preeval_data *) xdata; - tree t = *tp; - - /* If we find the base object, obviously we have overlap. */ - if (data->lhs_base_decl == t) - return t; - - /* If the constructor component is indirect, determine if we have a - potential overlap with the lhs. The only bits of information we - have to go on at this point are addressability and alias sets. */ - if ((INDIRECT_REF_P (t) - || TREE_CODE (t) == MEM_REF) - && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl)) - && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t))) - return t; - - /* If the constructor component is a call, determine if it can hide a - potential overlap with the lhs through an INDIRECT_REF like above. - ??? Ugh - this is completely broken. In fact this whole analysis - doesn't look conservative. */ - if (TREE_CODE (t) == CALL_EXPR) - { - tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t))); - - for (type = TYPE_ARG_TYPES (fntype); type; type = TREE_CHAIN (type)) - if (POINTER_TYPE_P (TREE_VALUE (type)) - && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl)) - && alias_sets_conflict_p (data->lhs_alias_set, - get_alias_set - (TREE_TYPE (TREE_VALUE (type))))) - return t; - } - - if (IS_TYPE_OR_DECL_P (t)) - *walk_subtrees = 0; - return NULL; -} - -/* A subroutine of gimplify_init_constructor. Pre-evaluate EXPR, - force values that overlap with the lhs (as described by *DATA) - into temporaries. */ - -static void -gimplify_init_ctor_preeval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - struct gimplify_init_ctor_preeval_data *data) -{ - enum gimplify_status one; - - /* If the value is constant, then there's nothing to pre-evaluate. */ - if (TREE_CONSTANT (*expr_p)) - { - /* Ensure it does not have side effects, it might contain a reference to - the object we're initializing. */ - gcc_assert (!TREE_SIDE_EFFECTS (*expr_p)); - return; - } - - /* If the type has non-trivial constructors, we can't pre-evaluate. */ - if (TREE_ADDRESSABLE (TREE_TYPE (*expr_p))) - return; - - /* Recurse for nested constructors. */ - if (TREE_CODE (*expr_p) == CONSTRUCTOR) - { - unsigned HOST_WIDE_INT ix; - constructor_elt *ce; - vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (*expr_p); - - FOR_EACH_VEC_SAFE_ELT (v, ix, ce) - gimplify_init_ctor_preeval (&ce->value, pre_p, post_p, data); - - return; - } - - /* If this is a variable sized type, we must remember the size. */ - maybe_with_size_expr (expr_p); - - /* Gimplify the constructor element to something appropriate for the rhs - of a MODIFY_EXPR. Given that we know the LHS is an aggregate, we know - the gimplifier will consider this a store to memory. Doing this - gimplification now means that we won't have to deal with complicated - language-specific trees, nor trees like SAVE_EXPR that can induce - exponential search behavior. */ - one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue); - if (one == GS_ERROR) - { - *expr_p = NULL; - return; - } - - /* If we gimplified to a bare decl, we can be sure that it doesn't overlap - with the lhs, since "a = { .x=a }" doesn't make sense. This will - always be true for all scalars, since is_gimple_mem_rhs insists on a - temporary variable for them. */ - if (DECL_P (*expr_p)) - return; - - /* If this is of variable size, we have no choice but to assume it doesn't - overlap since we can't make a temporary for it. */ - if (TREE_CODE (TYPE_SIZE (TREE_TYPE (*expr_p))) != INTEGER_CST) - return; - - /* Otherwise, we must search for overlap ... */ - if (!walk_tree (expr_p, gimplify_init_ctor_preeval_1, data, NULL)) - return; - - /* ... and if found, force the value into a temporary. */ - *expr_p = get_formal_tmp_var (*expr_p, pre_p); -} - -/* A subroutine of gimplify_init_ctor_eval. Create a loop for - a RANGE_EXPR in a CONSTRUCTOR for an array. - - var = lower; - loop_entry: - object[var] = value; - if (var == upper) - goto loop_exit; - var = var + 1; - goto loop_entry; - loop_exit: - - We increment var _after_ the loop exit check because we might otherwise - fail if upper == TYPE_MAX_VALUE (type for upper). - - Note that we never have to deal with SAVE_EXPRs here, because this has - already been taken care of for us, in gimplify_init_ctor_preeval(). */ - -static void gimplify_init_ctor_eval (tree, vec<constructor_elt, va_gc> *, - gimple_seq *, bool); - -static void -gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, - tree value, tree array_elt_type, - gimple_seq *pre_p, bool cleared) -{ - tree loop_entry_label, loop_exit_label, fall_thru_label; - tree var, var_type, cref, tmp; - - loop_entry_label = create_artificial_label (UNKNOWN_LOCATION); - loop_exit_label = create_artificial_label (UNKNOWN_LOCATION); - fall_thru_label = create_artificial_label (UNKNOWN_LOCATION); - - /* Create and initialize the index variable. */ - var_type = TREE_TYPE (upper); - var = create_tmp_var (var_type); - gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, lower)); - - /* Add the loop entry label. */ - gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_entry_label)); - - /* Build the reference. */ - cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object), - var, NULL_TREE, NULL_TREE); - - /* If we are a constructor, just call gimplify_init_ctor_eval to do - the store. Otherwise just assign value to the reference. */ - - if (TREE_CODE (value) == CONSTRUCTOR) - /* NB we might have to call ourself recursively through - gimplify_init_ctor_eval if the value is a constructor. */ - gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value), - pre_p, cleared); - else - { - if (gimplify_expr (&value, pre_p, NULL, is_gimple_val, fb_rvalue) - != GS_ERROR) - gimplify_seq_add_stmt (pre_p, gimple_build_assign (cref, value)); - } - - /* We exit the loop when the index var is equal to the upper bound. */ - gimplify_seq_add_stmt (pre_p, - gimple_build_cond (EQ_EXPR, var, upper, - loop_exit_label, fall_thru_label)); - - gimplify_seq_add_stmt (pre_p, gimple_build_label (fall_thru_label)); - - /* Otherwise, increment the index var... */ - tmp = build2 (PLUS_EXPR, var_type, var, - fold_convert (var_type, integer_one_node)); - gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, tmp)); - - /* ...and jump back to the loop entry. */ - gimplify_seq_add_stmt (pre_p, gimple_build_goto (loop_entry_label)); - - /* Add the loop exit label. */ - gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_exit_label)); -} - -/* A subroutine of gimplify_init_constructor. Generate individual - MODIFY_EXPRs for a CONSTRUCTOR. OBJECT is the LHS against which the - assignments should happen. ELTS is the CONSTRUCTOR_ELTS of the - CONSTRUCTOR. CLEARED is true if the entire LHS object has been - zeroed first. */ - -static void -gimplify_init_ctor_eval (tree object, vec<constructor_elt, va_gc> *elts, - gimple_seq *pre_p, bool cleared) -{ - tree array_elt_type = NULL; - unsigned HOST_WIDE_INT ix; - tree purpose, value; - - if (TREE_CODE (TREE_TYPE (object)) == ARRAY_TYPE) - array_elt_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object))); - - FOR_EACH_CONSTRUCTOR_ELT (elts, ix, purpose, value) - { - tree cref; - - /* NULL values are created above for gimplification errors. */ - if (value == NULL) - continue; - - if (cleared && initializer_zerop (value)) - continue; - - /* ??? Here's to hoping the front end fills in all of the indices, - so we don't have to figure out what's missing ourselves. */ - gcc_assert (purpose); - - /* Skip zero-sized fields, unless value has side-effects. This can - happen with calls to functions returning a empty type, which - we shouldn't discard. As a number of downstream passes don't - expect sets of empty type fields, we rely on the gimplification of - the MODIFY_EXPR we make below to drop the assignment statement. */ - if (!TREE_SIDE_EFFECTS (value) - && TREE_CODE (purpose) == FIELD_DECL - && is_empty_type (TREE_TYPE (purpose))) - continue; - - /* If we have a RANGE_EXPR, we have to build a loop to assign the - whole range. */ - if (TREE_CODE (purpose) == RANGE_EXPR) - { - tree lower = TREE_OPERAND (purpose, 0); - tree upper = TREE_OPERAND (purpose, 1); - - /* If the lower bound is equal to upper, just treat it as if - upper was the index. */ - if (simple_cst_equal (lower, upper)) - purpose = upper; - else - { - gimplify_init_ctor_eval_range (object, lower, upper, value, - array_elt_type, pre_p, cleared); - continue; - } - } - - if (array_elt_type) - { - /* Do not use bitsizetype for ARRAY_REF indices. */ - if (TYPE_DOMAIN (TREE_TYPE (object))) - purpose - = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))), - purpose); - cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object), - purpose, NULL_TREE, NULL_TREE); - } - else - { - gcc_assert (TREE_CODE (purpose) == FIELD_DECL); - cref = build3 (COMPONENT_REF, TREE_TYPE (purpose), - unshare_expr (object), purpose, NULL_TREE); - } - - if (TREE_CODE (value) == CONSTRUCTOR - && TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE) - gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value), - pre_p, cleared); - else - { - tree init = build2 (INIT_EXPR, TREE_TYPE (cref), cref, value); - gimplify_and_add (init, pre_p); - ggc_free (init); - } - } -} - -/* Return the appropriate RHS predicate for this LHS. */ - -gimple_predicate -rhs_predicate_for (tree lhs) -{ - if (is_gimple_reg (lhs)) - return is_gimple_reg_rhs_or_call; - else - return is_gimple_mem_rhs_or_call; -} - -/* Return the initial guess for an appropriate RHS predicate for this LHS, - before the LHS has been gimplified. */ - -static gimple_predicate -initial_rhs_predicate_for (tree lhs) -{ - if (is_gimple_reg_type (TREE_TYPE (lhs))) - return is_gimple_reg_rhs_or_call; - else - return is_gimple_mem_rhs_or_call; -} - -/* Gimplify a C99 compound literal expression. This just means adding - the DECL_EXPR before the current statement and using its anonymous - decl instead. */ - -static enum gimplify_status -gimplify_compound_literal_expr (tree *expr_p, gimple_seq *pre_p, - bool (*gimple_test_f) (tree), - fallback_t fallback) -{ - tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (*expr_p); - tree decl = DECL_EXPR_DECL (decl_s); - tree init = DECL_INITIAL (decl); - /* Mark the decl as addressable if the compound literal - expression is addressable now, otherwise it is marked too late - after we gimplify the initialization expression. */ - if (TREE_ADDRESSABLE (*expr_p)) - TREE_ADDRESSABLE (decl) = 1; - /* Otherwise, if we don't need an lvalue and have a literal directly - substitute it. Check if it matches the gimple predicate, as - otherwise we'd generate a new temporary, and we can as well just - use the decl we already have. */ - else if (!TREE_ADDRESSABLE (decl) - && !TREE_THIS_VOLATILE (decl) - && init - && (fallback & fb_lvalue) == 0 - && gimple_test_f (init)) - { - *expr_p = init; - return GS_OK; - } - - /* If the decl is not addressable, then it is being used in some - expression or on the right hand side of a statement, and it can - be put into a readonly data section. */ - if (!TREE_ADDRESSABLE (decl) && (fallback & fb_lvalue) == 0) - TREE_READONLY (decl) = 1; - - /* This decl isn't mentioned in the enclosing block, so add it to the - list of temps. FIXME it seems a bit of a kludge to say that - anonymous artificial vars aren't pushed, but everything else is. */ - if (DECL_NAME (decl) == NULL_TREE && !DECL_SEEN_IN_BIND_EXPR_P (decl)) - gimple_add_tmp_var (decl); - - gimplify_and_add (decl_s, pre_p); - *expr_p = decl; - return GS_OK; -} - -/* Optimize embedded COMPOUND_LITERAL_EXPRs within a CONSTRUCTOR, - return a new CONSTRUCTOR if something changed. */ - -static tree -optimize_compound_literals_in_ctor (tree orig_ctor) -{ - tree ctor = orig_ctor; - vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor); - unsigned int idx, num = vec_safe_length (elts); - - for (idx = 0; idx < num; idx++) - { - tree value = (*elts)[idx].value; - tree newval = value; - if (TREE_CODE (value) == CONSTRUCTOR) - newval = optimize_compound_literals_in_ctor (value); - else if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR) - { - tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (value); - tree decl = DECL_EXPR_DECL (decl_s); - tree init = DECL_INITIAL (decl); - - if (!TREE_ADDRESSABLE (value) - && !TREE_ADDRESSABLE (decl) - && init - && TREE_CODE (init) == CONSTRUCTOR) - newval = optimize_compound_literals_in_ctor (init); - } - if (newval == value) - continue; - - if (ctor == orig_ctor) - { - ctor = copy_node (orig_ctor); - CONSTRUCTOR_ELTS (ctor) = vec_safe_copy (elts); - elts = CONSTRUCTOR_ELTS (ctor); - } - (*elts)[idx].value = newval; - } - return ctor; -} - -/* A subroutine of gimplify_modify_expr. Break out elements of a - CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs. - - Note that we still need to clear any elements that don't have explicit - initializers, so if not all elements are initialized we keep the - original MODIFY_EXPR, we just remove all of the constructor elements. - - If NOTIFY_TEMP_CREATION is true, do not gimplify, just return - GS_ERROR if we would have to create a temporary when gimplifying - this constructor. Otherwise, return GS_OK. - - If NOTIFY_TEMP_CREATION is false, just do the gimplification. */ - -static enum gimplify_status -gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool want_value, bool notify_temp_creation) -{ - tree object, ctor, type; - enum gimplify_status ret; - vec<constructor_elt, va_gc> *elts; - bool cleared = false; - bool is_empty_ctor = false; - bool is_init_expr = (TREE_CODE (*expr_p) == INIT_EXPR); - - gcc_assert (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == CONSTRUCTOR); - - if (!notify_temp_creation) - { - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_lvalue, fb_lvalue); - if (ret == GS_ERROR) - return ret; - } - - object = TREE_OPERAND (*expr_p, 0); - ctor = TREE_OPERAND (*expr_p, 1) - = optimize_compound_literals_in_ctor (TREE_OPERAND (*expr_p, 1)); - type = TREE_TYPE (ctor); - elts = CONSTRUCTOR_ELTS (ctor); - ret = GS_ALL_DONE; - - switch (TREE_CODE (type)) - { - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - case ARRAY_TYPE: - { - /* Use readonly data for initializers of this or smaller size - regardless of the num_nonzero_elements / num_unique_nonzero_elements - ratio. */ - const HOST_WIDE_INT min_unique_size = 64; - /* If num_nonzero_elements / num_unique_nonzero_elements ratio - is smaller than this, use readonly data. */ - const int unique_nonzero_ratio = 8; - /* True if a single access of the object must be ensured. This is the - case if the target is volatile, the type is non-addressable and more - than one field need to be assigned. */ - const bool ensure_single_access - = TREE_THIS_VOLATILE (object) - && !TREE_ADDRESSABLE (type) - && vec_safe_length (elts) > 1; - struct gimplify_init_ctor_preeval_data preeval_data; - HOST_WIDE_INT num_ctor_elements, num_nonzero_elements; - HOST_WIDE_INT num_unique_nonzero_elements; - bool complete_p, valid_const_initializer; - - /* Aggregate types must lower constructors to initialization of - individual elements. The exception is that a CONSTRUCTOR node - with no elements indicates zero-initialization of the whole. */ - if (vec_safe_is_empty (elts)) - { - if (notify_temp_creation) - return GS_OK; - is_empty_ctor = true; - break; - } - - /* Fetch information about the constructor to direct later processing. - We might want to make static versions of it in various cases, and - can only do so if it known to be a valid constant initializer. */ - valid_const_initializer - = categorize_ctor_elements (ctor, &num_nonzero_elements, - &num_unique_nonzero_elements, - &num_ctor_elements, &complete_p); - - /* If a const aggregate variable is being initialized, then it - should never be a lose to promote the variable to be static. */ - if (valid_const_initializer - && num_nonzero_elements > 1 - && TREE_READONLY (object) - && VAR_P (object) - && !DECL_REGISTER (object) - && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object)) - /* For ctors that have many repeated nonzero elements - represented through RANGE_EXPRs, prefer initializing - those through runtime loops over copies of large amounts - of data from readonly data section. */ - && (num_unique_nonzero_elements - > num_nonzero_elements / unique_nonzero_ratio - || ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) - <= (unsigned HOST_WIDE_INT) min_unique_size))) - { - if (notify_temp_creation) - return GS_ERROR; - - DECL_INITIAL (object) = ctor; - TREE_STATIC (object) = 1; - if (!DECL_NAME (object)) - DECL_NAME (object) = create_tmp_var_name ("C"); - walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL); - - /* ??? C++ doesn't automatically append a .<number> to the - assembler name, and even when it does, it looks at FE private - data structures to figure out what that number should be, - which are not set for this variable. I suppose this is - important for local statics for inline functions, which aren't - "local" in the object file sense. So in order to get a unique - TU-local symbol, we must invoke the lhd version now. */ - lhd_set_decl_assembler_name (object); - - *expr_p = NULL_TREE; - break; - } - - /* If there are "lots" of initialized elements, even discounting - those that are not address constants (and thus *must* be - computed at runtime), then partition the constructor into - constant and non-constant parts. Block copy the constant - parts in, then generate code for the non-constant parts. */ - /* TODO. There's code in cp/typeck.c to do this. */ - - if (int_size_in_bytes (TREE_TYPE (ctor)) < 0) - /* store_constructor will ignore the clearing of variable-sized - objects. Initializers for such objects must explicitly set - every field that needs to be set. */ - cleared = false; - else if (!complete_p) - /* If the constructor isn't complete, clear the whole object - beforehand, unless CONSTRUCTOR_NO_CLEARING is set on it. - - ??? This ought not to be needed. For any element not present - in the initializer, we should simply set them to zero. Except - we'd need to *find* the elements that are not present, and that - requires trickery to avoid quadratic compile-time behavior in - large cases or excessive memory use in small cases. */ - cleared = !CONSTRUCTOR_NO_CLEARING (ctor); - else if (num_ctor_elements - num_nonzero_elements - > CLEAR_RATIO (optimize_function_for_speed_p (cfun)) - && num_nonzero_elements < num_ctor_elements / 4) - /* If there are "lots" of zeros, it's more efficient to clear - the memory and then set the nonzero elements. */ - cleared = true; - else if (ensure_single_access && num_nonzero_elements == 0) - /* If a single access to the target must be ensured and all elements - are zero, then it's optimal to clear whatever their number. */ - cleared = true; - else - cleared = false; - - /* If there are "lots" of initialized elements, and all of them - are valid address constants, then the entire initializer can - be dropped to memory, and then memcpy'd out. Don't do this - for sparse arrays, though, as it's more efficient to follow - the standard CONSTRUCTOR behavior of memset followed by - individual element initialization. Also don't do this for small - all-zero initializers (which aren't big enough to merit - clearing), and don't try to make bitwise copies of - TREE_ADDRESSABLE types. */ - if (valid_const_initializer - && complete_p - && !(cleared || num_nonzero_elements == 0) - && !TREE_ADDRESSABLE (type)) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - unsigned int align; - - /* ??? We can still get unbounded array types, at least - from the C++ front end. This seems wrong, but attempt - to work around it for now. */ - if (size < 0) - { - size = int_size_in_bytes (TREE_TYPE (object)); - if (size >= 0) - TREE_TYPE (ctor) = type = TREE_TYPE (object); - } - - /* Find the maximum alignment we can assume for the object. */ - /* ??? Make use of DECL_OFFSET_ALIGN. */ - if (DECL_P (object)) - align = DECL_ALIGN (object); - else - align = TYPE_ALIGN (type); - - /* Do a block move either if the size is so small as to make - each individual move a sub-unit move on average, or if it - is so large as to make individual moves inefficient. */ - if (size > 0 - && num_nonzero_elements > 1 - /* For ctors that have many repeated nonzero elements - represented through RANGE_EXPRs, prefer initializing - those through runtime loops over copies of large amounts - of data from readonly data section. */ - && (num_unique_nonzero_elements - > num_nonzero_elements / unique_nonzero_ratio - || size <= min_unique_size) - && (size < num_nonzero_elements - || !can_move_by_pieces (size, align))) - { - if (notify_temp_creation) - return GS_ERROR; - - walk_tree (&ctor, force_labels_r, NULL, NULL); - ctor = tree_output_constant_def (ctor); - if (!useless_type_conversion_p (type, TREE_TYPE (ctor))) - ctor = build1 (VIEW_CONVERT_EXPR, type, ctor); - TREE_OPERAND (*expr_p, 1) = ctor; - - /* This is no longer an assignment of a CONSTRUCTOR, but - we still may have processing to do on the LHS. So - pretend we didn't do anything here to let that happen. */ - return GS_UNHANDLED; - } - } - - /* If a single access to the target must be ensured and there are - nonzero elements or the zero elements are not assigned en masse, - initialize the target from a temporary. */ - if (ensure_single_access && (num_nonzero_elements > 0 || !cleared)) - { - if (notify_temp_creation) - return GS_ERROR; - - tree temp = create_tmp_var (TYPE_MAIN_VARIANT (type)); - TREE_OPERAND (*expr_p, 0) = temp; - *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), - *expr_p, - build2 (MODIFY_EXPR, void_type_node, - object, temp)); - return GS_OK; - } - - if (notify_temp_creation) - return GS_OK; - - /* If there are nonzero elements and if needed, pre-evaluate to capture - elements overlapping with the lhs into temporaries. We must do this - before clearing to fetch the values before they are zeroed-out. */ - if (num_nonzero_elements > 0 && TREE_CODE (*expr_p) != INIT_EXPR) - { - preeval_data.lhs_base_decl = get_base_address (object); - if (!DECL_P (preeval_data.lhs_base_decl)) - preeval_data.lhs_base_decl = NULL; - preeval_data.lhs_alias_set = get_alias_set (object); - - gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1), - pre_p, post_p, &preeval_data); - } - - bool ctor_has_side_effects_p - = TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1)); - - if (cleared) - { - /* Zap the CONSTRUCTOR element list, which simplifies this case. - Note that we still have to gimplify, in order to handle the - case of variable sized types. Avoid shared tree structures. */ - CONSTRUCTOR_ELTS (ctor) = NULL; - TREE_SIDE_EFFECTS (ctor) = 0; - object = unshare_expr (object); - gimplify_stmt (expr_p, pre_p); - } - - /* If we have not block cleared the object, or if there are nonzero - elements in the constructor, or if the constructor has side effects, - add assignments to the individual scalar fields of the object. */ - if (!cleared - || num_nonzero_elements > 0 - || ctor_has_side_effects_p) - gimplify_init_ctor_eval (object, elts, pre_p, cleared); - - *expr_p = NULL_TREE; - } - break; - - case COMPLEX_TYPE: - { - tree r, i; - - if (notify_temp_creation) - return GS_OK; - - /* Extract the real and imaginary parts out of the ctor. */ - gcc_assert (elts->length () == 2); - r = (*elts)[0].value; - i = (*elts)[1].value; - if (r == NULL || i == NULL) - { - tree zero = build_zero_cst (TREE_TYPE (type)); - if (r == NULL) - r = zero; - if (i == NULL) - i = zero; - } - - /* Complex types have either COMPLEX_CST or COMPLEX_EXPR to - represent creation of a complex value. */ - if (TREE_CONSTANT (r) && TREE_CONSTANT (i)) - { - ctor = build_complex (type, r, i); - TREE_OPERAND (*expr_p, 1) = ctor; - } - else - { - ctor = build2 (COMPLEX_EXPR, type, r, i); - TREE_OPERAND (*expr_p, 1) = ctor; - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), - pre_p, - post_p, - rhs_predicate_for (TREE_OPERAND (*expr_p, 0)), - fb_rvalue); - } - } - break; - - case VECTOR_TYPE: - { - unsigned HOST_WIDE_INT ix; - constructor_elt *ce; - - if (notify_temp_creation) - return GS_OK; - - /* Go ahead and simplify constant constructors to VECTOR_CST. */ - if (TREE_CONSTANT (ctor)) - { - bool constant_p = true; - tree value; - - /* Even when ctor is constant, it might contain non-*_CST - elements, such as addresses or trapping values like - 1.0/0.0 - 1.0/0.0. Such expressions don't belong - in VECTOR_CST nodes. */ - FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value) - if (!CONSTANT_CLASS_P (value)) - { - constant_p = false; - break; - } - - if (constant_p) - { - TREE_OPERAND (*expr_p, 1) = build_vector_from_ctor (type, elts); - break; - } - - TREE_CONSTANT (ctor) = 0; - } - - /* Vector types use CONSTRUCTOR all the way through gimple - compilation as a general initializer. */ - FOR_EACH_VEC_SAFE_ELT (elts, ix, ce) - { - enum gimplify_status tret; - tret = gimplify_expr (&ce->value, pre_p, post_p, is_gimple_val, - fb_rvalue); - if (tret == GS_ERROR) - ret = GS_ERROR; - else if (TREE_STATIC (ctor) - && !initializer_constant_valid_p (ce->value, - TREE_TYPE (ce->value))) - TREE_STATIC (ctor) = 0; - } - recompute_constructor_flags (ctor); - if (!is_gimple_reg (TREE_OPERAND (*expr_p, 0))) - TREE_OPERAND (*expr_p, 1) = get_formal_tmp_var (ctor, pre_p); - } - break; - - default: - /* So how did we get a CONSTRUCTOR for a scalar type? */ - gcc_unreachable (); - } - - if (ret == GS_ERROR) - return GS_ERROR; - /* If we have gimplified both sides of the initializer but have - not emitted an assignment, do so now. */ - if (*expr_p) - { - tree lhs = TREE_OPERAND (*expr_p, 0); - tree rhs = TREE_OPERAND (*expr_p, 1); - if (want_value && object == lhs) - lhs = unshare_expr (lhs); - gassign *init = gimple_build_assign (lhs, rhs); - gimplify_seq_add_stmt (pre_p, init); - } - if (want_value) - { - *expr_p = object; - ret = GS_OK; - } - else - { - *expr_p = NULL; - ret = GS_ALL_DONE; - } - - /* If the user requests to initialize automatic variables, we - should initialize paddings inside the variable. Add a call to - __builtin_clear_pading (&object, 0, for_auto_init = true) to - initialize paddings of object always to zero regardless of - INIT_TYPE. Note, we will not insert this call if the aggregate - variable has be completely cleared already or it's initialized - with an empty constructor. We cannot insert this call if the - variable is a gimple register since __builtin_clear_padding will take - the address of the variable. As a result, if a long double/_Complex long - double variable will be spilled into stack later, its padding cannot - be cleared with __builtin_clear_padding. We should clear its padding - when it is spilled into memory. */ - if (is_init_expr - && !is_gimple_reg (object) - && clear_padding_type_may_have_padding_p (type) - && ((AGGREGATE_TYPE_P (type) && !cleared && !is_empty_ctor) - || !AGGREGATE_TYPE_P (type)) - && is_var_need_auto_init (object)) - gimple_add_padding_init_for_auto_var (object, false, pre_p); - - return ret; -} - -/* Given a pointer value OP0, return a simplified version of an - indirection through OP0, or NULL_TREE if no simplification is - possible. This may only be applied to a rhs of an expression. - Note that the resulting type may be different from the type pointed - to in the sense that it is still compatible from the langhooks - point of view. */ - -static tree -gimple_fold_indirect_ref_rhs (tree t) -{ - return gimple_fold_indirect_ref (t); -} - -/* Subroutine of gimplify_modify_expr to do simplifications of - MODIFY_EXPRs based on the code of the RHS. We loop for as long as - something changes. */ - -static enum gimplify_status -gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, - gimple_seq *pre_p, gimple_seq *post_p, - bool want_value) -{ - enum gimplify_status ret = GS_UNHANDLED; - bool changed; - - do - { - changed = false; - switch (TREE_CODE (*from_p)) - { - case VAR_DECL: - /* If we're assigning from a read-only variable initialized with - a constructor and not volatile, do the direct assignment from - the constructor, but only if the target is not volatile either - since this latter assignment might end up being done on a per - field basis. However, if the target is volatile and the type - is aggregate and non-addressable, gimplify_init_constructor - knows that it needs to ensure a single access to the target - and it will return GS_OK only in this case. */ - if (TREE_READONLY (*from_p) - && DECL_INITIAL (*from_p) - && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR - && !TREE_THIS_VOLATILE (*from_p) - && (!TREE_THIS_VOLATILE (*to_p) - || (AGGREGATE_TYPE_P (TREE_TYPE (*to_p)) - && !TREE_ADDRESSABLE (TREE_TYPE (*to_p))))) - { - tree old_from = *from_p; - enum gimplify_status subret; - - /* Move the constructor into the RHS. */ - *from_p = unshare_expr (DECL_INITIAL (*from_p)); - - /* Let's see if gimplify_init_constructor will need to put - it in memory. */ - subret = gimplify_init_constructor (expr_p, NULL, NULL, - false, true); - if (subret == GS_ERROR) - { - /* If so, revert the change. */ - *from_p = old_from; - } - else - { - ret = GS_OK; - changed = true; - } - } - break; - case INDIRECT_REF: - { - /* If we have code like - - *(const A*)(A*)&x - - where the type of "x" is a (possibly cv-qualified variant - of "A"), treat the entire expression as identical to "x". - This kind of code arises in C++ when an object is bound - to a const reference, and if "x" is a TARGET_EXPR we want - to take advantage of the optimization below. */ - bool volatile_p = TREE_THIS_VOLATILE (*from_p); - tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); - if (t) - { - if (TREE_THIS_VOLATILE (t) != volatile_p) - { - if (DECL_P (t)) - t = build_simple_mem_ref_loc (EXPR_LOCATION (*from_p), - build_fold_addr_expr (t)); - if (REFERENCE_CLASS_P (t)) - TREE_THIS_VOLATILE (t) = volatile_p; - } - *from_p = t; - ret = GS_OK; - changed = true; - } - break; - } - - case TARGET_EXPR: - { - /* If we are initializing something from a TARGET_EXPR, strip the - TARGET_EXPR and initialize it directly, if possible. This can't - be done if the initializer is void, since that implies that the - temporary is set in some non-trivial way. - - ??? What about code that pulls out the temp and uses it - elsewhere? I think that such code never uses the TARGET_EXPR as - an initializer. If I'm wrong, we'll die because the temp won't - have any RTL. In that case, I guess we'll need to replace - references somehow. */ - tree init = TARGET_EXPR_INITIAL (*from_p); - - if (init - && (TREE_CODE (*expr_p) != MODIFY_EXPR - || !TARGET_EXPR_NO_ELIDE (*from_p)) - && !VOID_TYPE_P (TREE_TYPE (init))) - { - *from_p = init; - ret = GS_OK; - changed = true; - } - } - break; - - case COMPOUND_EXPR: - /* Remove any COMPOUND_EXPR in the RHS so the following cases will be - caught. */ - gimplify_compound_expr (from_p, pre_p, true); - ret = GS_OK; - changed = true; - break; - - case CONSTRUCTOR: - /* If we already made some changes, let the front end have a - crack at this before we break it down. */ - if (ret != GS_UNHANDLED) - break; - - /* If we're initializing from a CONSTRUCTOR, break this into - individual MODIFY_EXPRs. */ - ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value, - false); - return ret; - - case COND_EXPR: - /* If we're assigning to a non-register type, push the assignment - down into the branches. This is mandatory for ADDRESSABLE types, - since we cannot generate temporaries for such, but it saves a - copy in other cases as well. */ - if (!is_gimple_reg_type (TREE_TYPE (*from_p))) - { - /* This code should mirror the code in gimplify_cond_expr. */ - enum tree_code code = TREE_CODE (*expr_p); - tree cond = *from_p; - tree result = *to_p; - - ret = gimplify_expr (&result, pre_p, post_p, - is_gimple_lvalue, fb_lvalue); - if (ret != GS_ERROR) - ret = GS_OK; - - /* If we are going to write RESULT more than once, clear - TREE_READONLY flag, otherwise we might incorrectly promote - the variable to static const and initialize it at compile - time in one of the branches. */ - if (VAR_P (result) - && TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node - && TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) - TREE_READONLY (result) = 0; - if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node) - TREE_OPERAND (cond, 1) - = build2 (code, void_type_node, result, - TREE_OPERAND (cond, 1)); - if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) - TREE_OPERAND (cond, 2) - = build2 (code, void_type_node, unshare_expr (result), - TREE_OPERAND (cond, 2)); - - TREE_TYPE (cond) = void_type_node; - recalculate_side_effects (cond); - - if (want_value) - { - gimplify_and_add (cond, pre_p); - *expr_p = unshare_expr (result); - } - else - *expr_p = cond; - return ret; - } - break; - - case CALL_EXPR: - /* For calls that return in memory, give *to_p as the CALL_EXPR's - return slot so that we don't generate a temporary. */ - if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p) - && aggregate_value_p (*from_p, *from_p)) - { - bool use_target; - - if (!(rhs_predicate_for (*to_p))(*from_p)) - /* If we need a temporary, *to_p isn't accurate. */ - use_target = false; - /* It's OK to use the return slot directly unless it's an NRV. */ - else if (TREE_CODE (*to_p) == RESULT_DECL - && DECL_NAME (*to_p) == NULL_TREE - && needs_to_live_in_memory (*to_p)) - use_target = true; - else if (is_gimple_reg_type (TREE_TYPE (*to_p)) - || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) - /* Don't force regs into memory. */ - use_target = false; - else if (TREE_CODE (*expr_p) == INIT_EXPR) - /* It's OK to use the target directly if it's being - initialized. */ - use_target = true; - else if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) - != INTEGER_CST) - /* Always use the target and thus RSO for variable-sized types. - GIMPLE cannot deal with a variable-sized assignment - embedded in a call statement. */ - use_target = true; - else if (TREE_CODE (*to_p) != SSA_NAME - && (!is_gimple_variable (*to_p) - || needs_to_live_in_memory (*to_p))) - /* Don't use the original target if it's already addressable; - if its address escapes, and the called function uses the - NRV optimization, a conforming program could see *to_p - change before the called function returns; see c++/19317. - When optimizing, the return_slot pass marks more functions - as safe after we have escape info. */ - use_target = false; - else - use_target = true; - - if (use_target) - { - CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; - mark_addressable (*to_p); - } - } - break; - - case WITH_SIZE_EXPR: - /* Likewise for calls that return an aggregate of non-constant size, - since we would not be able to generate a temporary at all. */ - if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR) - { - *from_p = TREE_OPERAND (*from_p, 0); - /* We don't change ret in this case because the - WITH_SIZE_EXPR might have been added in - gimplify_modify_expr, so returning GS_OK would lead to an - infinite loop. */ - changed = true; - } - break; - - /* If we're initializing from a container, push the initialization - inside it. */ - case CLEANUP_POINT_EXPR: - case BIND_EXPR: - case STATEMENT_LIST: - { - tree wrap = *from_p; - tree t; - - ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval, - fb_lvalue); - if (ret != GS_ERROR) - ret = GS_OK; - - t = voidify_wrapper_expr (wrap, *expr_p); - gcc_assert (t == *expr_p); - - if (want_value) - { - gimplify_and_add (wrap, pre_p); - *expr_p = unshare_expr (*to_p); - } - else - *expr_p = wrap; - return GS_OK; - } - - case NOP_EXPR: - /* Pull out compound literal expressions from a NOP_EXPR. - Those are created in the C FE to drop qualifiers during - lvalue conversion. */ - if ((TREE_CODE (TREE_OPERAND (*from_p, 0)) == COMPOUND_LITERAL_EXPR) - && tree_ssa_useless_type_conversion (*from_p)) - { - *from_p = TREE_OPERAND (*from_p, 0); - ret = GS_OK; - changed = true; - } - break; - - case COMPOUND_LITERAL_EXPR: - { - tree complit = TREE_OPERAND (*expr_p, 1); - tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit); - tree decl = DECL_EXPR_DECL (decl_s); - tree init = DECL_INITIAL (decl); - - /* struct T x = (struct T) { 0, 1, 2 } can be optimized - into struct T x = { 0, 1, 2 } if the address of the - compound literal has never been taken. */ - if (!TREE_ADDRESSABLE (complit) - && !TREE_ADDRESSABLE (decl) - && init) - { - *expr_p = copy_node (*expr_p); - TREE_OPERAND (*expr_p, 1) = init; - return GS_OK; - } - } - - default: - break; - } - } - while (changed); - - return ret; -} - - -/* Return true if T looks like a valid GIMPLE statement. */ - -static bool -is_gimple_stmt (tree t) -{ - const enum tree_code code = TREE_CODE (t); - - switch (code) - { - case NOP_EXPR: - /* The only valid NOP_EXPR is the empty statement. */ - return IS_EMPTY_STMT (t); - - case BIND_EXPR: - case COND_EXPR: - /* These are only valid if they're void. */ - return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t)); - - case SWITCH_EXPR: - case GOTO_EXPR: - case RETURN_EXPR: - case LABEL_EXPR: - case CASE_LABEL_EXPR: - case TRY_CATCH_EXPR: - case TRY_FINALLY_EXPR: - case EH_FILTER_EXPR: - case CATCH_EXPR: - case ASM_EXPR: - case STATEMENT_LIST: - case OACC_PARALLEL: - case OACC_KERNELS: - case OACC_SERIAL: - case OACC_DATA: - case OACC_HOST_DATA: - case OACC_DECLARE: - case OACC_UPDATE: - case OACC_ENTER_DATA: - case OACC_EXIT_DATA: - case OACC_CACHE: - case OMP_PARALLEL: - case OMP_FOR: - case OMP_SIMD: - case OMP_DISTRIBUTE: - case OMP_LOOP: - case OACC_LOOP: - case OMP_SCAN: - case OMP_SCOPE: - case OMP_SECTIONS: - case OMP_SECTION: - case OMP_SINGLE: - case OMP_MASTER: - case OMP_MASKED: - case OMP_TASKGROUP: - case OMP_ORDERED: - case OMP_CRITICAL: - case OMP_TASK: - case OMP_TARGET: - case OMP_TARGET_DATA: - case OMP_TARGET_UPDATE: - case OMP_TARGET_ENTER_DATA: - case OMP_TARGET_EXIT_DATA: - case OMP_TASKLOOP: - case OMP_TEAMS: - /* These are always void. */ - return true; - - case CALL_EXPR: - case MODIFY_EXPR: - case PREDICT_EXPR: - /* These are valid regardless of their type. */ - return true; - - default: - return false; - } -} - - -/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is - a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a gimple register. - - IMPORTANT NOTE: This promotion is performed by introducing a load of the - other, unmodified part of the complex object just before the total store. - As a consequence, if the object is still uninitialized, an undefined value - will be loaded into a register, which may result in a spurious exception - if the register is floating-point and the value happens to be a signaling - NaN for example. Then the fully-fledged complex operations lowering pass - followed by a DCE pass are necessary in order to fix things up. */ - -static enum gimplify_status -gimplify_modify_expr_complex_part (tree *expr_p, gimple_seq *pre_p, - bool want_value) -{ - enum tree_code code, ocode; - tree lhs, rhs, new_rhs, other, realpart, imagpart; - - lhs = TREE_OPERAND (*expr_p, 0); - rhs = TREE_OPERAND (*expr_p, 1); - code = TREE_CODE (lhs); - lhs = TREE_OPERAND (lhs, 0); - - ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR; - other = build1 (ocode, TREE_TYPE (rhs), lhs); - suppress_warning (other); - other = get_formal_tmp_var (other, pre_p); - - realpart = code == REALPART_EXPR ? rhs : other; - imagpart = code == REALPART_EXPR ? other : rhs; - - if (TREE_CONSTANT (realpart) && TREE_CONSTANT (imagpart)) - new_rhs = build_complex (TREE_TYPE (lhs), realpart, imagpart); - else - new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart); - - gimplify_seq_add_stmt (pre_p, gimple_build_assign (lhs, new_rhs)); - *expr_p = (want_value) ? rhs : NULL_TREE; - - return GS_ALL_DONE; -} - -/* Gimplify the MODIFY_EXPR node pointed to by EXPR_P. - - modify_expr - : varname '=' rhs - | '*' ID '=' rhs - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. - - POST_P points to the list where side effects that must happen after - *EXPR_P should be stored. - - WANT_VALUE is nonzero iff we want to use the value of this expression - in another expression. */ - -static enum gimplify_status -gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool want_value) -{ - tree *from_p = &TREE_OPERAND (*expr_p, 1); - tree *to_p = &TREE_OPERAND (*expr_p, 0); - enum gimplify_status ret = GS_UNHANDLED; - gimple *assign; - location_t loc = EXPR_LOCATION (*expr_p); - gimple_stmt_iterator gsi; - - gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR - || TREE_CODE (*expr_p) == INIT_EXPR); - - /* Trying to simplify a clobber using normal logic doesn't work, - so handle it here. */ - if (TREE_CLOBBER_P (*from_p)) - { - ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - if (ret == GS_ERROR) - return ret; - gcc_assert (!want_value); - if (!VAR_P (*to_p) && TREE_CODE (*to_p) != MEM_REF) - { - tree addr = get_initialized_tmp_var (build_fold_addr_expr (*to_p), - pre_p, post_p); - *to_p = build_simple_mem_ref_loc (EXPR_LOCATION (*to_p), addr); - } - gimplify_seq_add_stmt (pre_p, gimple_build_assign (*to_p, *from_p)); - *expr_p = NULL; - return GS_ALL_DONE; - } - - /* Insert pointer conversions required by the middle-end that are not - required by the frontend. This fixes middle-end type checking for - for example gcc.dg/redecl-6.c. */ - if (POINTER_TYPE_P (TREE_TYPE (*to_p))) - { - STRIP_USELESS_TYPE_CONVERSION (*from_p); - if (!useless_type_conversion_p (TREE_TYPE (*to_p), TREE_TYPE (*from_p))) - *from_p = fold_convert_loc (loc, TREE_TYPE (*to_p), *from_p); - } - - /* See if any simplifications can be done based on what the RHS is. */ - ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p, - want_value); - if (ret != GS_UNHANDLED) - return ret; - - /* For empty types only gimplify the left hand side and right hand - side as statements and throw away the assignment. Do this after - gimplify_modify_expr_rhs so we handle TARGET_EXPRs of addressable - types properly. */ - if (is_empty_type (TREE_TYPE (*from_p)) - && !want_value - /* Don't do this for calls that return addressable types, expand_call - relies on those having a lhs. */ - && !(TREE_ADDRESSABLE (TREE_TYPE (*from_p)) - && TREE_CODE (*from_p) == CALL_EXPR)) - { - gimplify_stmt (from_p, pre_p); - gimplify_stmt (to_p, pre_p); - *expr_p = NULL_TREE; - return GS_ALL_DONE; - } - - /* If the value being copied is of variable width, compute the length - of the copy into a WITH_SIZE_EXPR. Note that we need to do this - before gimplifying any of the operands so that we can resolve any - PLACEHOLDER_EXPRs in the size. Also note that the RTL expander uses - the size of the expression to be copied, not of the destination, so - that is what we must do here. */ - maybe_with_size_expr (from_p); - - /* As a special case, we have to temporarily allow for assignments - with a CALL_EXPR on the RHS. Since in GIMPLE a function call is - a toplevel statement, when gimplifying the GENERIC expression - MODIFY_EXPR <a, CALL_EXPR <foo>>, we cannot create the tuple - GIMPLE_ASSIGN <a, GIMPLE_CALL <foo>>. - - Instead, we need to create the tuple GIMPLE_CALL <a, foo>. To - prevent gimplify_expr from trying to create a new temporary for - foo's LHS, we tell it that it should only gimplify until it - reaches the CALL_EXPR. On return from gimplify_expr, the newly - created GIMPLE_CALL <foo> will be the last statement in *PRE_P - and all we need to do here is set 'a' to be its LHS. */ - - /* Gimplify the RHS first for C++17 and bug 71104. */ - gimple_predicate initial_pred = initial_rhs_predicate_for (*to_p); - ret = gimplify_expr (from_p, pre_p, post_p, initial_pred, fb_rvalue); - if (ret == GS_ERROR) - return ret; - - /* Then gimplify the LHS. */ - /* If we gimplified the RHS to a CALL_EXPR and that call may return - twice we have to make sure to gimplify into non-SSA as otherwise - the abnormal edge added later will make those defs not dominate - their uses. - ??? Technically this applies only to the registers used in the - resulting non-register *TO_P. */ - bool saved_into_ssa = gimplify_ctxp->into_ssa; - if (saved_into_ssa - && TREE_CODE (*from_p) == CALL_EXPR - && call_expr_flags (*from_p) & ECF_RETURNS_TWICE) - gimplify_ctxp->into_ssa = false; - ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - gimplify_ctxp->into_ssa = saved_into_ssa; - if (ret == GS_ERROR) - return ret; - - /* Now that the LHS is gimplified, re-gimplify the RHS if our initial - guess for the predicate was wrong. */ - gimple_predicate final_pred = rhs_predicate_for (*to_p); - if (final_pred != initial_pred) - { - ret = gimplify_expr (from_p, pre_p, post_p, final_pred, fb_rvalue); - if (ret == GS_ERROR) - return ret; - } - - /* In case of va_arg internal fn wrappped in a WITH_SIZE_EXPR, add the type - size as argument to the call. */ - if (TREE_CODE (*from_p) == WITH_SIZE_EXPR) - { - tree call = TREE_OPERAND (*from_p, 0); - tree vlasize = TREE_OPERAND (*from_p, 1); - - if (TREE_CODE (call) == CALL_EXPR - && CALL_EXPR_IFN (call) == IFN_VA_ARG) - { - int nargs = call_expr_nargs (call); - tree type = TREE_TYPE (call); - tree ap = CALL_EXPR_ARG (call, 0); - tree tag = CALL_EXPR_ARG (call, 1); - tree aptag = CALL_EXPR_ARG (call, 2); - tree newcall = build_call_expr_internal_loc (EXPR_LOCATION (call), - IFN_VA_ARG, type, - nargs + 1, ap, tag, - aptag, vlasize); - TREE_OPERAND (*from_p, 0) = newcall; - } - } - - /* Now see if the above changed *from_p to something we handle specially. */ - ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p, - want_value); - if (ret != GS_UNHANDLED) - return ret; - - /* If we've got a variable sized assignment between two lvalues (i.e. does - not involve a call), then we can make things a bit more straightforward - by converting the assignment to memcpy or memset. */ - if (TREE_CODE (*from_p) == WITH_SIZE_EXPR) - { - tree from = TREE_OPERAND (*from_p, 0); - tree size = TREE_OPERAND (*from_p, 1); - - if (TREE_CODE (from) == CONSTRUCTOR) - return gimplify_modify_expr_to_memset (expr_p, size, want_value, pre_p); - - if (is_gimple_addressable (from)) - { - *from_p = from; - return gimplify_modify_expr_to_memcpy (expr_p, size, want_value, - pre_p); - } - } - - /* Transform partial stores to non-addressable complex variables into - total stores. This allows us to use real instead of virtual operands - for these variables, which improves optimization. */ - if ((TREE_CODE (*to_p) == REALPART_EXPR - || TREE_CODE (*to_p) == IMAGPART_EXPR) - && is_gimple_reg (TREE_OPERAND (*to_p, 0))) - return gimplify_modify_expr_complex_part (expr_p, pre_p, want_value); - - /* Try to alleviate the effects of the gimplification creating artificial - temporaries (see for example is_gimple_reg_rhs) on the debug info, but - make sure not to create DECL_DEBUG_EXPR links across functions. */ - if (!gimplify_ctxp->into_ssa - && VAR_P (*from_p) - && DECL_IGNORED_P (*from_p) - && DECL_P (*to_p) - && !DECL_IGNORED_P (*to_p) - && decl_function_context (*to_p) == current_function_decl - && decl_function_context (*from_p) == current_function_decl) - { - if (!DECL_NAME (*from_p) && DECL_NAME (*to_p)) - DECL_NAME (*from_p) - = create_tmp_var_name (IDENTIFIER_POINTER (DECL_NAME (*to_p))); - DECL_HAS_DEBUG_EXPR_P (*from_p) = 1; - SET_DECL_DEBUG_EXPR (*from_p, *to_p); - } - - if (want_value && TREE_THIS_VOLATILE (*to_p)) - *from_p = get_initialized_tmp_var (*from_p, pre_p, post_p); - - if (TREE_CODE (*from_p) == CALL_EXPR) - { - /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL - instead of a GIMPLE_ASSIGN. */ - gcall *call_stmt; - if (CALL_EXPR_FN (*from_p) == NULL_TREE) - { - /* Gimplify internal functions created in the FEs. */ - int nargs = call_expr_nargs (*from_p), i; - enum internal_fn ifn = CALL_EXPR_IFN (*from_p); - auto_vec<tree> vargs (nargs); - - for (i = 0; i < nargs; i++) - { - gimplify_arg (&CALL_EXPR_ARG (*from_p, i), pre_p, - EXPR_LOCATION (*from_p)); - vargs.quick_push (CALL_EXPR_ARG (*from_p, i)); - } - call_stmt = gimple_build_call_internal_vec (ifn, vargs); - gimple_call_set_nothrow (call_stmt, TREE_NOTHROW (*from_p)); - gimple_set_location (call_stmt, EXPR_LOCATION (*expr_p)); - } - else - { - tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p)); - CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0); - STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p)); - tree fndecl = get_callee_fndecl (*from_p); - if (fndecl - && fndecl_built_in_p (fndecl, BUILT_IN_EXPECT) - && call_expr_nargs (*from_p) == 3) - call_stmt = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3, - CALL_EXPR_ARG (*from_p, 0), - CALL_EXPR_ARG (*from_p, 1), - CALL_EXPR_ARG (*from_p, 2)); - else - { - call_stmt = gimple_build_call_from_tree (*from_p, fnptrtype); - } - } - notice_special_calls (call_stmt); - if (!gimple_call_noreturn_p (call_stmt) || !should_remove_lhs_p (*to_p)) - gimple_call_set_lhs (call_stmt, *to_p); - else if (TREE_CODE (*to_p) == SSA_NAME) - /* The above is somewhat premature, avoid ICEing later for a - SSA name w/o a definition. We may have uses in the GIMPLE IL. - ??? This doesn't make it a default-def. */ - SSA_NAME_DEF_STMT (*to_p) = gimple_build_nop (); - - assign = call_stmt; - } - else - { - assign = gimple_build_assign (*to_p, *from_p); - gimple_set_location (assign, EXPR_LOCATION (*expr_p)); - if (COMPARISON_CLASS_P (*from_p)) - copy_warning (assign, *from_p); - } - - if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p)) - { - /* We should have got an SSA name from the start. */ - gcc_assert (TREE_CODE (*to_p) == SSA_NAME - || ! gimple_in_ssa_p (cfun)); - } - - gimplify_seq_add_stmt (pre_p, assign); - gsi = gsi_last (*pre_p); - maybe_fold_stmt (&gsi); - - if (want_value) - { - *expr_p = TREE_THIS_VOLATILE (*to_p) ? *from_p : unshare_expr (*to_p); - return GS_OK; - } - else - *expr_p = NULL; - - return GS_ALL_DONE; -} - -/* Gimplify a comparison between two variable-sized objects. Do this - with a call to BUILT_IN_MEMCMP. */ - -static enum gimplify_status -gimplify_variable_sized_compare (tree *expr_p) -{ - location_t loc = EXPR_LOCATION (*expr_p); - tree op0 = TREE_OPERAND (*expr_p, 0); - tree op1 = TREE_OPERAND (*expr_p, 1); - tree t, arg, dest, src, expr; - - arg = TYPE_SIZE_UNIT (TREE_TYPE (op0)); - arg = unshare_expr (arg); - arg = SUBSTITUTE_PLACEHOLDER_IN_EXPR (arg, op0); - src = build_fold_addr_expr_loc (loc, op1); - dest = build_fold_addr_expr_loc (loc, op0); - t = builtin_decl_implicit (BUILT_IN_MEMCMP); - t = build_call_expr_loc (loc, t, 3, dest, src, arg); - - expr - = build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node); - SET_EXPR_LOCATION (expr, loc); - *expr_p = expr; - - return GS_OK; -} - -/* Gimplify a comparison between two aggregate objects of integral scalar - mode as a comparison between the bitwise equivalent scalar values. */ - -static enum gimplify_status -gimplify_scalar_mode_aggregate_compare (tree *expr_p) -{ - location_t loc = EXPR_LOCATION (*expr_p); - tree op0 = TREE_OPERAND (*expr_p, 0); - tree op1 = TREE_OPERAND (*expr_p, 1); - - tree type = TREE_TYPE (op0); - tree scalar_type = lang_hooks.types.type_for_mode (TYPE_MODE (type), 1); - - op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op0); - op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op1); - - *expr_p - = fold_build2_loc (loc, TREE_CODE (*expr_p), TREE_TYPE (*expr_p), op0, op1); - - return GS_OK; -} - -/* Gimplify an expression sequence. This function gimplifies each - expression and rewrites the original expression with the last - expression of the sequence in GIMPLE form. - - PRE_P points to the list where the side effects for all the - expressions in the sequence will be emitted. - - WANT_VALUE is true when the result of the last COMPOUND_EXPR is used. */ - -static enum gimplify_status -gimplify_compound_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) -{ - tree t = *expr_p; - - do - { - tree *sub_p = &TREE_OPERAND (t, 0); - - if (TREE_CODE (*sub_p) == COMPOUND_EXPR) - gimplify_compound_expr (sub_p, pre_p, false); - else - gimplify_stmt (sub_p, pre_p); - - t = TREE_OPERAND (t, 1); - } - while (TREE_CODE (t) == COMPOUND_EXPR); - - *expr_p = t; - if (want_value) - return GS_OK; - else - { - gimplify_stmt (expr_p, pre_p); - return GS_ALL_DONE; - } -} - -/* Gimplify a SAVE_EXPR node. EXPR_P points to the expression to - gimplify. After gimplification, EXPR_P will point to a new temporary - that holds the original value of the SAVE_EXPR node. - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. */ - -static enum gimplify_status -gimplify_save_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - enum gimplify_status ret = GS_ALL_DONE; - tree val; - - gcc_assert (TREE_CODE (*expr_p) == SAVE_EXPR); - val = TREE_OPERAND (*expr_p, 0); - - if (TREE_TYPE (val) == error_mark_node) - return GS_ERROR; - - /* If the SAVE_EXPR has not been resolved, then evaluate it once. */ - if (!SAVE_EXPR_RESOLVED_P (*expr_p)) - { - /* The operand may be a void-valued expression. It is - being executed only for its side-effects. */ - if (TREE_TYPE (val) == void_type_node) - { - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_stmt, fb_none); - val = NULL; - } - else - /* The temporary may not be an SSA name as later abnormal and EH - control flow may invalidate use/def domination. When in SSA - form then assume there are no such issues and SAVE_EXPRs only - appear via GENERIC foldings. */ - val = get_initialized_tmp_var (val, pre_p, post_p, - gimple_in_ssa_p (cfun)); - - TREE_OPERAND (*expr_p, 0) = val; - SAVE_EXPR_RESOLVED_P (*expr_p) = 1; - } - - *expr_p = val; - - return ret; -} - -/* Rewrite the ADDR_EXPR node pointed to by EXPR_P - - unary_expr - : ... - | '&' varname - ... - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. - - POST_P points to the list where side effects that must happen after - *EXPR_P should be stored. */ - -static enum gimplify_status -gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - tree expr = *expr_p; - tree op0 = TREE_OPERAND (expr, 0); - enum gimplify_status ret; - location_t loc = EXPR_LOCATION (*expr_p); - - switch (TREE_CODE (op0)) - { - case INDIRECT_REF: - do_indirect_ref: - /* Check if we are dealing with an expression of the form '&*ptr'. - While the front end folds away '&*ptr' into 'ptr', these - expressions may be generated internally by the compiler (e.g., - builtins like __builtin_va_end). */ - /* Caution: the silent array decomposition semantics we allow for - ADDR_EXPR means we can't always discard the pair. */ - /* Gimplification of the ADDR_EXPR operand may drop - cv-qualification conversions, so make sure we add them if - needed. */ - { - tree op00 = TREE_OPERAND (op0, 0); - tree t_expr = TREE_TYPE (expr); - tree t_op00 = TREE_TYPE (op00); - - if (!useless_type_conversion_p (t_expr, t_op00)) - op00 = fold_convert_loc (loc, TREE_TYPE (expr), op00); - *expr_p = op00; - ret = GS_OK; - } - break; - - case VIEW_CONVERT_EXPR: - /* Take the address of our operand and then convert it to the type of - this ADDR_EXPR. - - ??? The interactions of VIEW_CONVERT_EXPR and aliasing is not at - all clear. The impact of this transformation is even less clear. */ - - /* If the operand is a useless conversion, look through it. Doing so - guarantees that the ADDR_EXPR and its operand will remain of the - same type. */ - if (tree_ssa_useless_type_conversion (TREE_OPERAND (op0, 0))) - op0 = TREE_OPERAND (op0, 0); - - *expr_p = fold_convert_loc (loc, TREE_TYPE (expr), - build_fold_addr_expr_loc (loc, - TREE_OPERAND (op0, 0))); - ret = GS_OK; - break; - - case MEM_REF: - if (integer_zerop (TREE_OPERAND (op0, 1))) - goto do_indirect_ref; - - /* fall through */ - - default: - /* If we see a call to a declared builtin or see its address - being taken (we can unify those cases here) then we can mark - the builtin for implicit generation by GCC. */ - if (TREE_CODE (op0) == FUNCTION_DECL - && fndecl_built_in_p (op0, BUILT_IN_NORMAL) - && builtin_decl_declared_p (DECL_FUNCTION_CODE (op0))) - set_builtin_decl_implicit_p (DECL_FUNCTION_CODE (op0), true); - - /* We use fb_either here because the C frontend sometimes takes - the address of a call that returns a struct; see - gcc.dg/c99-array-lval-1.c. The gimplifier will correctly make - the implied temporary explicit. */ - - /* Make the operand addressable. */ - ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p, - is_gimple_addressable, fb_either); - if (ret == GS_ERROR) - break; - - /* Then mark it. Beware that it may not be possible to do so directly - if a temporary has been created by the gimplification. */ - prepare_gimple_addressable (&TREE_OPERAND (expr, 0), pre_p); - - op0 = TREE_OPERAND (expr, 0); - - /* For various reasons, the gimplification of the expression - may have made a new INDIRECT_REF. */ - if (TREE_CODE (op0) == INDIRECT_REF - || (TREE_CODE (op0) == MEM_REF - && integer_zerop (TREE_OPERAND (op0, 1)))) - goto do_indirect_ref; - - mark_addressable (TREE_OPERAND (expr, 0)); - - /* The FEs may end up building ADDR_EXPRs early on a decl with - an incomplete type. Re-build ADDR_EXPRs in canonical form - here. */ - if (!types_compatible_p (TREE_TYPE (op0), TREE_TYPE (TREE_TYPE (expr)))) - *expr_p = build_fold_addr_expr (op0); - - /* Make sure TREE_CONSTANT and TREE_SIDE_EFFECTS are set properly. */ - recompute_tree_invariant_for_addr_expr (*expr_p); - - /* If we re-built the ADDR_EXPR add a conversion to the original type - if required. */ - if (!useless_type_conversion_p (TREE_TYPE (expr), TREE_TYPE (*expr_p))) - *expr_p = fold_convert (TREE_TYPE (expr), *expr_p); - - break; - } - - return ret; -} - -/* Gimplify the operands of an ASM_EXPR. Input operands should be a gimple - value; output operands should be a gimple lvalue. */ - -static enum gimplify_status -gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - tree expr; - int noutputs; - const char **oconstraints; - int i; - tree link; - const char *constraint; - bool allows_mem, allows_reg, is_inout; - enum gimplify_status ret, tret; - gasm *stmt; - vec<tree, va_gc> *inputs; - vec<tree, va_gc> *outputs; - vec<tree, va_gc> *clobbers; - vec<tree, va_gc> *labels; - tree link_next; - - expr = *expr_p; - noutputs = list_length (ASM_OUTPUTS (expr)); - oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); - - inputs = NULL; - outputs = NULL; - clobbers = NULL; - labels = NULL; - - ret = GS_ALL_DONE; - link_next = NULL_TREE; - for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = link_next) - { - bool ok; - size_t constraint_len; - - link_next = TREE_CHAIN (link); - - oconstraints[i] - = constraint - = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - constraint_len = strlen (constraint); - if (constraint_len == 0) - continue; - - ok = parse_output_constraint (&constraint, i, 0, 0, - &allows_mem, &allows_reg, &is_inout); - if (!ok) - { - ret = GS_ERROR; - is_inout = false; - } - - /* If we can't make copies, we can only accept memory. - Similarly for VLAs. */ - tree outtype = TREE_TYPE (TREE_VALUE (link)); - if (outtype != error_mark_node - && (TREE_ADDRESSABLE (outtype) - || !COMPLETE_TYPE_P (outtype) - || !tree_fits_poly_uint64_p (TYPE_SIZE_UNIT (outtype)))) - { - if (allows_mem) - allows_reg = 0; - else - { - error ("impossible constraint in %<asm%>"); - error ("non-memory output %d must stay in memory", i); - return GS_ERROR; - } - } - - if (!allows_reg && allows_mem) - mark_addressable (TREE_VALUE (link)); - - tree orig = TREE_VALUE (link); - tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, - is_inout ? is_gimple_min_lval : is_gimple_lvalue, - fb_lvalue | fb_mayfail); - if (tret == GS_ERROR) - { - if (orig != error_mark_node) - error ("invalid lvalue in %<asm%> output %d", i); - ret = tret; - } - - /* If the constraint does not allow memory make sure we gimplify - it to a register if it is not already but its base is. This - happens for complex and vector components. */ - if (!allows_mem) - { - tree op = TREE_VALUE (link); - if (! is_gimple_val (op) - && is_gimple_reg_type (TREE_TYPE (op)) - && is_gimple_reg (get_base_address (op))) - { - tree tem = create_tmp_reg (TREE_TYPE (op)); - tree ass; - if (is_inout) - { - ass = build2 (MODIFY_EXPR, TREE_TYPE (tem), - tem, unshare_expr (op)); - gimplify_and_add (ass, pre_p); - } - ass = build2 (MODIFY_EXPR, TREE_TYPE (tem), op, tem); - gimplify_and_add (ass, post_p); - - TREE_VALUE (link) = tem; - tret = GS_OK; - } - } - - vec_safe_push (outputs, link); - TREE_CHAIN (link) = NULL_TREE; - - if (is_inout) - { - /* An input/output operand. To give the optimizers more - flexibility, split it into separate input and output - operands. */ - tree input; - /* Buffer big enough to format a 32-bit UINT_MAX into. */ - char buf[11]; - - /* Turn the in/out constraint into an output constraint. */ - char *p = xstrdup (constraint); - p[0] = '='; - TREE_VALUE (TREE_PURPOSE (link)) = build_string (constraint_len, p); - - /* And add a matching input constraint. */ - if (allows_reg) - { - sprintf (buf, "%u", i); - - /* If there are multiple alternatives in the constraint, - handle each of them individually. Those that allow register - will be replaced with operand number, the others will stay - unchanged. */ - if (strchr (p, ',') != NULL) - { - size_t len = 0, buflen = strlen (buf); - char *beg, *end, *str, *dst; - - for (beg = p + 1;;) - { - end = strchr (beg, ','); - if (end == NULL) - end = strchr (beg, '\0'); - if ((size_t) (end - beg) < buflen) - len += buflen + 1; - else - len += end - beg + 1; - if (*end) - beg = end + 1; - else - break; - } - - str = (char *) alloca (len); - for (beg = p + 1, dst = str;;) - { - const char *tem; - bool mem_p, reg_p, inout_p; - - end = strchr (beg, ','); - if (end) - *end = '\0'; - beg[-1] = '='; - tem = beg - 1; - parse_output_constraint (&tem, i, 0, 0, - &mem_p, ®_p, &inout_p); - if (dst != str) - *dst++ = ','; - if (reg_p) - { - memcpy (dst, buf, buflen); - dst += buflen; - } - else - { - if (end) - len = end - beg; - else - len = strlen (beg); - memcpy (dst, beg, len); - dst += len; - } - if (end) - beg = end + 1; - else - break; - } - *dst = '\0'; - input = build_string (dst - str, str); - } - else - input = build_string (strlen (buf), buf); - } - else - input = build_string (constraint_len - 1, constraint + 1); - - free (p); - - input = build_tree_list (build_tree_list (NULL_TREE, input), - unshare_expr (TREE_VALUE (link))); - ASM_INPUTS (expr) = chainon (ASM_INPUTS (expr), input); - } - } - - link_next = NULL_TREE; - for (link = ASM_INPUTS (expr); link; ++i, link = link_next) - { - link_next = TREE_CHAIN (link); - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - parse_input_constraint (&constraint, 0, 0, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); - - /* If we can't make copies, we can only accept memory. */ - tree intype = TREE_TYPE (TREE_VALUE (link)); - if (intype != error_mark_node - && (TREE_ADDRESSABLE (intype) - || !COMPLETE_TYPE_P (intype) - || !tree_fits_poly_uint64_p (TYPE_SIZE_UNIT (intype)))) - { - if (allows_mem) - allows_reg = 0; - else - { - error ("impossible constraint in %<asm%>"); - error ("non-memory input %d must stay in memory", i); - return GS_ERROR; - } - } - - /* If the operand is a memory input, it should be an lvalue. */ - if (!allows_reg && allows_mem) - { - tree inputv = TREE_VALUE (link); - STRIP_NOPS (inputv); - if (TREE_CODE (inputv) == PREDECREMENT_EXPR - || TREE_CODE (inputv) == PREINCREMENT_EXPR - || TREE_CODE (inputv) == POSTDECREMENT_EXPR - || TREE_CODE (inputv) == POSTINCREMENT_EXPR - || TREE_CODE (inputv) == MODIFY_EXPR) - TREE_VALUE (link) = error_mark_node; - tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, - is_gimple_lvalue, fb_lvalue | fb_mayfail); - if (tret != GS_ERROR) - { - /* Unlike output operands, memory inputs are not guaranteed - to be lvalues by the FE, and while the expressions are - marked addressable there, if it is e.g. a statement - expression, temporaries in it might not end up being - addressable. They might be already used in the IL and thus - it is too late to make them addressable now though. */ - tree x = TREE_VALUE (link); - while (handled_component_p (x)) - x = TREE_OPERAND (x, 0); - if (TREE_CODE (x) == MEM_REF - && TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) - x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); - if ((VAR_P (x) - || TREE_CODE (x) == PARM_DECL - || TREE_CODE (x) == RESULT_DECL) - && !TREE_ADDRESSABLE (x) - && is_gimple_reg (x)) - { - warning_at (EXPR_LOC_OR_LOC (TREE_VALUE (link), - input_location), 0, - "memory input %d is not directly addressable", - i); - prepare_gimple_addressable (&TREE_VALUE (link), pre_p); - } - } - mark_addressable (TREE_VALUE (link)); - if (tret == GS_ERROR) - { - if (inputv != error_mark_node) - error_at (EXPR_LOC_OR_LOC (TREE_VALUE (link), input_location), - "memory input %d is not directly addressable", i); - ret = tret; - } - } - else - { - tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, - is_gimple_asm_val, fb_rvalue); - if (tret == GS_ERROR) - ret = tret; - } - - TREE_CHAIN (link) = NULL_TREE; - vec_safe_push (inputs, link); - } - - link_next = NULL_TREE; - for (link = ASM_CLOBBERS (expr); link; ++i, link = link_next) - { - link_next = TREE_CHAIN (link); - TREE_CHAIN (link) = NULL_TREE; - vec_safe_push (clobbers, link); - } - - link_next = NULL_TREE; - for (link = ASM_LABELS (expr); link; ++i, link = link_next) - { - link_next = TREE_CHAIN (link); - TREE_CHAIN (link) = NULL_TREE; - vec_safe_push (labels, link); - } - - /* Do not add ASMs with errors to the gimple IL stream. */ - if (ret != GS_ERROR) - { - stmt = gimple_build_asm_vec (TREE_STRING_POINTER (ASM_STRING (expr)), - inputs, outputs, clobbers, labels); - - gimple_asm_set_volatile (stmt, ASM_VOLATILE_P (expr) || noutputs == 0); - gimple_asm_set_input (stmt, ASM_INPUT_P (expr)); - gimple_asm_set_inline (stmt, ASM_INLINE_P (expr)); - - gimplify_seq_add_stmt (pre_p, stmt); - } - - return ret; -} - -/* Gimplify a CLEANUP_POINT_EXPR. Currently this works by adding - GIMPLE_WITH_CLEANUP_EXPRs to the prequeue as we encounter cleanups while - gimplifying the body, and converting them to TRY_FINALLY_EXPRs when we - return to this function. - - FIXME should we complexify the prequeue handling instead? Or use flags - for all the cleanups and let the optimizer tighten them up? The current - code seems pretty fragile; it will break on a cleanup within any - non-conditional nesting. But any such nesting would be broken, anyway; - we can't write a TRY_FINALLY_EXPR that starts inside a nesting construct - and continues out of it. We can do that at the RTL level, though, so - having an optimizer to tighten up try/finally regions would be a Good - Thing. */ - -static enum gimplify_status -gimplify_cleanup_point_expr (tree *expr_p, gimple_seq *pre_p) -{ - gimple_stmt_iterator iter; - gimple_seq body_sequence = NULL; - - tree temp = voidify_wrapper_expr (*expr_p, NULL); - - /* We only care about the number of conditions between the innermost - CLEANUP_POINT_EXPR and the cleanup. So save and reset the count and - any cleanups collected outside the CLEANUP_POINT_EXPR. */ - int old_conds = gimplify_ctxp->conditions; - gimple_seq old_cleanups = gimplify_ctxp->conditional_cleanups; - bool old_in_cleanup_point_expr = gimplify_ctxp->in_cleanup_point_expr; - gimplify_ctxp->conditions = 0; - gimplify_ctxp->conditional_cleanups = NULL; - gimplify_ctxp->in_cleanup_point_expr = true; - - gimplify_stmt (&TREE_OPERAND (*expr_p, 0), &body_sequence); - - gimplify_ctxp->conditions = old_conds; - gimplify_ctxp->conditional_cleanups = old_cleanups; - gimplify_ctxp->in_cleanup_point_expr = old_in_cleanup_point_expr; - - for (iter = gsi_start (body_sequence); !gsi_end_p (iter); ) - { - gimple *wce = gsi_stmt (iter); - - if (gimple_code (wce) == GIMPLE_WITH_CLEANUP_EXPR) - { - if (gsi_one_before_end_p (iter)) - { - /* Note that gsi_insert_seq_before and gsi_remove do not - scan operands, unlike some other sequence mutators. */ - if (!gimple_wce_cleanup_eh_only (wce)) - gsi_insert_seq_before_without_update (&iter, - gimple_wce_cleanup (wce), - GSI_SAME_STMT); - gsi_remove (&iter, true); - break; - } - else - { - gtry *gtry; - gimple_seq seq; - enum gimple_try_flags kind; - - if (gimple_wce_cleanup_eh_only (wce)) - kind = GIMPLE_TRY_CATCH; - else - kind = GIMPLE_TRY_FINALLY; - seq = gsi_split_seq_after (iter); - - gtry = gimple_build_try (seq, gimple_wce_cleanup (wce), kind); - /* Do not use gsi_replace here, as it may scan operands. - We want to do a simple structural modification only. */ - gsi_set_stmt (&iter, gtry); - iter = gsi_start (gtry->eval); - } - } - else - gsi_next (&iter); - } - - gimplify_seq_add_seq (pre_p, body_sequence); - if (temp) - { - *expr_p = temp; - return GS_OK; - } - else - { - *expr_p = NULL; - return GS_ALL_DONE; - } -} - -/* Insert a cleanup marker for gimplify_cleanup_point_expr. CLEANUP - is the cleanup action required. EH_ONLY is true if the cleanup should - only be executed if an exception is thrown, not on normal exit. - If FORCE_UNCOND is true perform the cleanup unconditionally; this is - only valid for clobbers. */ - -static void -gimple_push_cleanup (tree var, tree cleanup, bool eh_only, gimple_seq *pre_p, - bool force_uncond = false) -{ - gimple *wce; - gimple_seq cleanup_stmts = NULL; - - /* Errors can result in improperly nested cleanups. Which results in - confusion when trying to resolve the GIMPLE_WITH_CLEANUP_EXPR. */ - if (seen_error ()) - return; - - if (gimple_conditional_context ()) - { - /* If we're in a conditional context, this is more complex. We only - want to run the cleanup if we actually ran the initialization that - necessitates it, but we want to run it after the end of the - conditional context. So we wrap the try/finally around the - condition and use a flag to determine whether or not to actually - run the destructor. Thus - - test ? f(A()) : 0 - - becomes (approximately) - - flag = 0; - try { - if (test) { A::A(temp); flag = 1; val = f(temp); } - else { val = 0; } - } finally { - if (flag) A::~A(temp); - } - val - */ - if (force_uncond) - { - gimplify_stmt (&cleanup, &cleanup_stmts); - wce = gimple_build_wce (cleanup_stmts); - gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, wce); - } - else - { - tree flag = create_tmp_var (boolean_type_node, "cleanup"); - gassign *ffalse = gimple_build_assign (flag, boolean_false_node); - gassign *ftrue = gimple_build_assign (flag, boolean_true_node); - - cleanup = build3 (COND_EXPR, void_type_node, flag, cleanup, NULL); - gimplify_stmt (&cleanup, &cleanup_stmts); - wce = gimple_build_wce (cleanup_stmts); - - gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, ffalse); - gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, wce); - gimplify_seq_add_stmt (pre_p, ftrue); - - /* Because of this manipulation, and the EH edges that jump - threading cannot redirect, the temporary (VAR) will appear - to be used uninitialized. Don't warn. */ - suppress_warning (var, OPT_Wuninitialized); - } - } - else - { - gimplify_stmt (&cleanup, &cleanup_stmts); - wce = gimple_build_wce (cleanup_stmts); - gimple_wce_set_cleanup_eh_only (wce, eh_only); - gimplify_seq_add_stmt (pre_p, wce); - } -} - -/* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR. */ - -static enum gimplify_status -gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - tree targ = *expr_p; - tree temp = TARGET_EXPR_SLOT (targ); - tree init = TARGET_EXPR_INITIAL (targ); - enum gimplify_status ret; - - bool unpoison_empty_seq = false; - gimple_stmt_iterator unpoison_it; - - if (init) - { - tree cleanup = NULL_TREE; - - /* TARGET_EXPR temps aren't part of the enclosing block, so add it - to the temps list. Handle also variable length TARGET_EXPRs. */ - if (!poly_int_tree_p (DECL_SIZE (temp))) - { - if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (temp))) - gimplify_type_sizes (TREE_TYPE (temp), pre_p); - /* FIXME: this is correct only when the size of the type does - not depend on expressions evaluated in init. */ - gimplify_vla_decl (temp, pre_p); - } - else - { - /* Save location where we need to place unpoisoning. It's possible - that a variable will be converted to needs_to_live_in_memory. */ - unpoison_it = gsi_last (*pre_p); - unpoison_empty_seq = gsi_end_p (unpoison_it); - - gimple_add_tmp_var (temp); - } - - /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the - expression is supposed to initialize the slot. */ - if (VOID_TYPE_P (TREE_TYPE (init))) - ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none); - else - { - tree init_expr = build2 (INIT_EXPR, void_type_node, temp, init); - init = init_expr; - ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none); - init = NULL; - ggc_free (init_expr); - } - if (ret == GS_ERROR) - { - /* PR c++/28266 Make sure this is expanded only once. */ - TARGET_EXPR_INITIAL (targ) = NULL_TREE; - return GS_ERROR; - } - if (init) - gimplify_and_add (init, pre_p); - - /* If needed, push the cleanup for the temp. */ - if (TARGET_EXPR_CLEANUP (targ)) - { - if (CLEANUP_EH_ONLY (targ)) - gimple_push_cleanup (temp, TARGET_EXPR_CLEANUP (targ), - CLEANUP_EH_ONLY (targ), pre_p); - else - cleanup = TARGET_EXPR_CLEANUP (targ); - } - - /* Add a clobber for the temporary going out of scope, like - gimplify_bind_expr. */ - if (gimplify_ctxp->in_cleanup_point_expr - && needs_to_live_in_memory (temp)) - { - if (flag_stack_reuse == SR_ALL) - { - tree clobber = build_clobber (TREE_TYPE (temp)); - clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber); - gimple_push_cleanup (temp, clobber, false, pre_p, true); - } - if (asan_poisoned_variables - && DECL_ALIGN (temp) <= MAX_SUPPORTED_STACK_ALIGNMENT - && !TREE_STATIC (temp) - && dbg_cnt (asan_use_after_scope) - && !gimplify_omp_ctxp) - { - tree asan_cleanup = build_asan_poison_call_expr (temp); - if (asan_cleanup) - { - if (unpoison_empty_seq) - unpoison_it = gsi_start (*pre_p); - - asan_poison_variable (temp, false, &unpoison_it, - unpoison_empty_seq); - gimple_push_cleanup (temp, asan_cleanup, false, pre_p); - } - } - } - if (cleanup) - gimple_push_cleanup (temp, cleanup, false, pre_p); - - /* Only expand this once. */ - TREE_OPERAND (targ, 3) = init; - TARGET_EXPR_INITIAL (targ) = NULL_TREE; - } - else - /* We should have expanded this before. */ - gcc_assert (DECL_SEEN_IN_BIND_EXPR_P (temp)); - - *expr_p = temp; - return GS_OK; -} - -/* Gimplification of expression trees. */ - -/* Gimplify an expression which appears at statement context. The - corresponding GIMPLE statements are added to *SEQ_P. If *SEQ_P is - NULL, a new sequence is allocated. - - Return true if we actually added a statement to the queue. */ - -bool -gimplify_stmt (tree *stmt_p, gimple_seq *seq_p) -{ - gimple_seq_node last; - - last = gimple_seq_last (*seq_p); - gimplify_expr (stmt_p, seq_p, NULL, is_gimple_stmt, fb_none); - return last != gimple_seq_last (*seq_p); -} - -/* Add FIRSTPRIVATE entries for DECL in the OpenMP the surrounding parallels - to CTX. If entries already exist, force them to be some flavor of private. - If there is no enclosing parallel, do nothing. */ - -void -omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl) -{ - splay_tree_node n; - - if (decl == NULL || !DECL_P (decl) || ctx->region_type == ORT_NONE) - return; - - do - { - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL) - { - if (n->value & GOVD_SHARED) - n->value = GOVD_FIRSTPRIVATE | (n->value & GOVD_SEEN); - else if (n->value & GOVD_MAP) - n->value |= GOVD_MAP_TO_ONLY; - else - return; - } - else if ((ctx->region_type & ORT_TARGET) != 0) - { - if (ctx->defaultmap[GDMK_SCALAR] & GOVD_FIRSTPRIVATE) - omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); - else - omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY); - } - else if (ctx->region_type != ORT_WORKSHARE - && ctx->region_type != ORT_TASKGROUP - && ctx->region_type != ORT_SIMD - && ctx->region_type != ORT_ACC - && !(ctx->region_type & ORT_TARGET_DATA)) - omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); - - ctx = ctx->outer_context; - } - while (ctx); -} - -/* Similarly for each of the type sizes of TYPE. */ - -static void -omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type) -{ - if (type == NULL || type == error_mark_node) - return; - type = TYPE_MAIN_VARIANT (type); - - if (ctx->privatized_types->add (type)) - return; - - switch (TREE_CODE (type)) - { - case INTEGER_TYPE: - case ENUMERAL_TYPE: - case BOOLEAN_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - omp_firstprivatize_variable (ctx, TYPE_MIN_VALUE (type)); - omp_firstprivatize_variable (ctx, TYPE_MAX_VALUE (type)); - break; - - case ARRAY_TYPE: - omp_firstprivatize_type_sizes (ctx, TREE_TYPE (type)); - omp_firstprivatize_type_sizes (ctx, TYPE_DOMAIN (type)); - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - { - tree field; - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL) - { - omp_firstprivatize_variable (ctx, DECL_FIELD_OFFSET (field)); - omp_firstprivatize_type_sizes (ctx, TREE_TYPE (field)); - } - } - break; - - case POINTER_TYPE: - case REFERENCE_TYPE: - omp_firstprivatize_type_sizes (ctx, TREE_TYPE (type)); - break; - - default: - break; - } - - omp_firstprivatize_variable (ctx, TYPE_SIZE (type)); - omp_firstprivatize_variable (ctx, TYPE_SIZE_UNIT (type)); - lang_hooks.types.omp_firstprivatize_type_sizes (ctx, type); -} - -/* Add an entry for DECL in the OMP context CTX with FLAGS. */ - -static void -omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) -{ - splay_tree_node n; - unsigned int nflags; - tree t; - - if (error_operand_p (decl) || ctx->region_type == ORT_NONE) - return; - - /* Never elide decls whose type has TREE_ADDRESSABLE set. This means - there are constructors involved somewhere. Exception is a shared clause, - there is nothing privatized in that case. */ - if ((flags & GOVD_SHARED) == 0 - && (TREE_ADDRESSABLE (TREE_TYPE (decl)) - || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))) - flags |= GOVD_SEEN; - - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) - { - /* We shouldn't be re-adding the decl with the same data - sharing class. */ - gcc_assert ((n->value & GOVD_DATA_SHARE_CLASS & flags) == 0); - nflags = n->value | flags; - /* The only combination of data sharing classes we should see is - FIRSTPRIVATE and LASTPRIVATE. However, OpenACC permits - reduction variables to be used in data sharing clauses. */ - gcc_assert ((ctx->region_type & ORT_ACC) != 0 - || ((nflags & GOVD_DATA_SHARE_CLASS) - == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE)) - || (flags & GOVD_DATA_SHARE_CLASS) == 0); - n->value = nflags; - return; - } - - /* When adding a variable-sized variable, we have to handle all sorts - of additional bits of data: the pointer replacement variable, and - the parameters of the type. */ - if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) - { - /* Add the pointer replacement variable as PRIVATE if the variable - replacement is private, else FIRSTPRIVATE since we'll need the - address of the original variable either for SHARED, or for the - copy into or out of the context. */ - if (!(flags & GOVD_LOCAL) && ctx->region_type != ORT_TASKGROUP) - { - if (flags & GOVD_MAP) - nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT; - else if (flags & GOVD_PRIVATE) - nflags = GOVD_PRIVATE; - else if (((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 - && (flags & GOVD_FIRSTPRIVATE)) - || (ctx->region_type == ORT_TARGET_DATA - && (flags & GOVD_DATA_SHARE_CLASS) == 0)) - nflags = GOVD_PRIVATE | GOVD_EXPLICIT; - else - nflags = GOVD_FIRSTPRIVATE; - nflags |= flags & GOVD_SEEN; - t = DECL_VALUE_EXPR (decl); - gcc_assert (TREE_CODE (t) == INDIRECT_REF); - t = TREE_OPERAND (t, 0); - gcc_assert (DECL_P (t)); - omp_add_variable (ctx, t, nflags); - } - - /* Add all of the variable and type parameters (which should have - been gimplified to a formal temporary) as FIRSTPRIVATE. */ - omp_firstprivatize_variable (ctx, DECL_SIZE_UNIT (decl)); - omp_firstprivatize_variable (ctx, DECL_SIZE (decl)); - omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl)); - - /* The variable-sized variable itself is never SHARED, only some form - of PRIVATE. The sharing would take place via the pointer variable - which we remapped above. */ - if (flags & GOVD_SHARED) - flags = GOVD_SHARED | GOVD_DEBUG_PRIVATE - | (flags & (GOVD_SEEN | GOVD_EXPLICIT)); - - /* We're going to make use of the TYPE_SIZE_UNIT at least in the - alloca statement we generate for the variable, so make sure it - is available. This isn't automatically needed for the SHARED - case, since we won't be allocating local storage then. - For local variables TYPE_SIZE_UNIT might not be gimplified yet, - in this case omp_notice_variable will be called later - on when it is gimplified. */ - else if (! (flags & (GOVD_LOCAL | GOVD_MAP)) - && DECL_P (TYPE_SIZE_UNIT (TREE_TYPE (decl)))) - omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true); - } - else if ((flags & (GOVD_MAP | GOVD_LOCAL)) == 0 - && omp_privatize_by_reference (decl)) - { - omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl)); - - /* Similar to the direct variable sized case above, we'll need the - size of references being privatized. */ - if ((flags & GOVD_SHARED) == 0) - { - t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl))); - if (t && DECL_P (t)) - omp_notice_variable (ctx, t, true); - } - } - - if (n != NULL) - n->value |= flags; - else - splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); - - /* For reductions clauses in OpenACC loop directives, by default create a - copy clause on the enclosing parallel construct for carrying back the - results. */ - if (ctx->region_type == ORT_ACC && (flags & GOVD_REDUCTION)) - { - struct gimplify_omp_ctx *outer_ctx = ctx->outer_context; - while (outer_ctx) - { - n = splay_tree_lookup (outer_ctx->variables, (splay_tree_key)decl); - if (n != NULL) - { - /* Ignore local variables and explicitly declared clauses. */ - if (n->value & (GOVD_LOCAL | GOVD_EXPLICIT)) - break; - else if (outer_ctx->region_type == ORT_ACC_KERNELS) - { - /* According to the OpenACC spec, such a reduction variable - should already have a copy map on a kernels construct, - verify that here. */ - gcc_assert (!(n->value & GOVD_FIRSTPRIVATE) - && (n->value & GOVD_MAP)); - } - else if (outer_ctx->region_type == ORT_ACC_PARALLEL) - { - /* Remove firstprivate and make it a copy map. */ - n->value &= ~GOVD_FIRSTPRIVATE; - n->value |= GOVD_MAP; - } - } - else if (outer_ctx->region_type == ORT_ACC_PARALLEL) - { - splay_tree_insert (outer_ctx->variables, (splay_tree_key)decl, - GOVD_MAP | GOVD_SEEN); - break; - } - outer_ctx = outer_ctx->outer_context; - } - } -} - -/* Notice a threadprivate variable DECL used in OMP context CTX. - This just prints out diagnostics about threadprivate variable uses - in untied tasks. If DECL2 is non-NULL, prevent this warning - on that variable. */ - -static bool -omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, - tree decl2) -{ - splay_tree_node n; - struct gimplify_omp_ctx *octx; - - for (octx = ctx; octx; octx = octx->outer_context) - if ((octx->region_type & ORT_TARGET) != 0 - || octx->order_concurrent) - { - n = splay_tree_lookup (octx->variables, (splay_tree_key)decl); - if (n == NULL) - { - if (octx->order_concurrent) - { - error ("threadprivate variable %qE used in a region with" - " %<order(concurrent)%> clause", DECL_NAME (decl)); - inform (octx->location, "enclosing region"); - } - else - { - error ("threadprivate variable %qE used in target region", - DECL_NAME (decl)); - inform (octx->location, "enclosing target region"); - } - splay_tree_insert (octx->variables, (splay_tree_key)decl, 0); - } - if (decl2) - splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0); - } - - if (ctx->region_type != ORT_UNTIED_TASK) - return false; - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n == NULL) - { - error ("threadprivate variable %qE used in untied task", - DECL_NAME (decl)); - inform (ctx->location, "enclosing task"); - splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0); - } - if (decl2) - splay_tree_insert (ctx->variables, (splay_tree_key)decl2, 0); - return false; -} - -/* Return true if global var DECL is device resident. */ - -static bool -device_resident_p (tree decl) -{ - tree attr = lookup_attribute ("oacc declare target", DECL_ATTRIBUTES (decl)); - - if (!attr) - return false; - - for (tree t = TREE_VALUE (attr); t; t = TREE_PURPOSE (t)) - { - tree c = TREE_VALUE (t); - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DEVICE_RESIDENT) - return true; - } - - return false; -} - -/* Return true if DECL has an ACC DECLARE attribute. */ - -static bool -is_oacc_declared (tree decl) -{ - tree t = TREE_CODE (decl) == MEM_REF ? TREE_OPERAND (decl, 0) : decl; - tree declared = lookup_attribute ("oacc declare target", DECL_ATTRIBUTES (t)); - return declared != NULL_TREE; -} - -/* Determine outer default flags for DECL mentioned in an OMP region - but not declared in an enclosing clause. - - ??? Some compiler-generated variables (like SAVE_EXPRs) could be - remapped firstprivate instead of shared. To some extent this is - addressed in omp_firstprivatize_type_sizes, but not - effectively. */ - -static unsigned -omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, - bool in_code, unsigned flags) -{ - enum omp_clause_default_kind default_kind = ctx->default_kind; - enum omp_clause_default_kind kind; - - kind = lang_hooks.decls.omp_predetermined_sharing (decl); - if (ctx->region_type & ORT_TASK) - { - tree detach_clause = omp_find_clause (ctx->clauses, OMP_CLAUSE_DETACH); - - /* The event-handle specified by a detach clause should always be firstprivate, - regardless of the current default. */ - if (detach_clause && OMP_CLAUSE_DECL (detach_clause) == decl) - kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - } - if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED) - default_kind = kind; - else if (VAR_P (decl) && TREE_STATIC (decl) && DECL_IN_CONSTANT_POOL (decl)) - default_kind = OMP_CLAUSE_DEFAULT_SHARED; - /* For C/C++ default({,first}private), variables with static storage duration - declared in a namespace or global scope and referenced in construct - must be explicitly specified, i.e. acts as default(none). */ - else if ((default_kind == OMP_CLAUSE_DEFAULT_PRIVATE - || default_kind == OMP_CLAUSE_DEFAULT_FIRSTPRIVATE) - && VAR_P (decl) - && is_global_var (decl) - && (DECL_FILE_SCOPE_P (decl) - || (DECL_CONTEXT (decl) - && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)) - && !lang_GNU_Fortran ()) - default_kind = OMP_CLAUSE_DEFAULT_NONE; - - switch (default_kind) - { - case OMP_CLAUSE_DEFAULT_NONE: - { - const char *rtype; - - if (ctx->region_type & ORT_PARALLEL) - rtype = "parallel"; - else if ((ctx->region_type & ORT_TASKLOOP) == ORT_TASKLOOP) - rtype = "taskloop"; - else if (ctx->region_type & ORT_TASK) - rtype = "task"; - else if (ctx->region_type & ORT_TEAMS) - rtype = "teams"; - else - gcc_unreachable (); - - error ("%qE not specified in enclosing %qs", - DECL_NAME (lang_hooks.decls.omp_report_decl (decl)), rtype); - inform (ctx->location, "enclosing %qs", rtype); - } - /* FALLTHRU */ - case OMP_CLAUSE_DEFAULT_SHARED: - flags |= GOVD_SHARED; - break; - case OMP_CLAUSE_DEFAULT_PRIVATE: - flags |= GOVD_PRIVATE; - break; - case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE: - flags |= GOVD_FIRSTPRIVATE; - break; - case OMP_CLAUSE_DEFAULT_UNSPECIFIED: - /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED. */ - gcc_assert ((ctx->region_type & ORT_TASK) != 0); - if (struct gimplify_omp_ctx *octx = ctx->outer_context) - { - omp_notice_variable (octx, decl, in_code); - for (; octx; octx = octx->outer_context) - { - splay_tree_node n2; - - n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl); - if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0 - && (n2 == NULL || (n2->value & GOVD_DATA_SHARE_CLASS) == 0)) - continue; - if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED) - { - flags |= GOVD_FIRSTPRIVATE; - goto found_outer; - } - if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0) - { - flags |= GOVD_SHARED; - goto found_outer; - } - } - } - - if (TREE_CODE (decl) == PARM_DECL - || (!is_global_var (decl) - && DECL_CONTEXT (decl) == current_function_decl)) - flags |= GOVD_FIRSTPRIVATE; - else - flags |= GOVD_SHARED; - found_outer: - break; - - default: - gcc_unreachable (); - } - - return flags; -} - - -/* Determine outer default flags for DECL mentioned in an OACC region - but not declared in an enclosing clause. */ - -static unsigned -oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) -{ - const char *rkind; - bool on_device = false; - bool is_private = false; - bool declared = is_oacc_declared (decl); - tree type = TREE_TYPE (decl); - - if (omp_privatize_by_reference (decl)) - type = TREE_TYPE (type); - - /* For Fortran COMMON blocks, only used variables in those blocks are - transfered and remapped. The block itself will have a private clause to - avoid transfering the data twice. - The hook evaluates to false by default. For a variable in Fortran's COMMON - or EQUIVALENCE block, returns 'true' (as we have shared=false) - as only - the variables in such a COMMON/EQUIVALENCE block shall be privatized not - the whole block. For C++ and Fortran, it can also be true under certain - other conditions, if DECL_HAS_VALUE_EXPR. */ - if (RECORD_OR_UNION_TYPE_P (type)) - is_private = lang_hooks.decls.omp_disregard_value_expr (decl, false); - - if ((ctx->region_type & (ORT_ACC_PARALLEL | ORT_ACC_KERNELS)) != 0 - && is_global_var (decl) - && device_resident_p (decl) - && !is_private) - { - on_device = true; - flags |= GOVD_MAP_TO_ONLY; - } - - switch (ctx->region_type) - { - case ORT_ACC_KERNELS: - rkind = "kernels"; - - if (is_private) - flags |= GOVD_FIRSTPRIVATE; - else if (AGGREGATE_TYPE_P (type)) - { - /* Aggregates default to 'present_or_copy', or 'present'. */ - if (ctx->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) - flags |= GOVD_MAP; - else - flags |= GOVD_MAP | GOVD_MAP_FORCE_PRESENT; - } - else - /* Scalars default to 'copy'. */ - flags |= GOVD_MAP | GOVD_MAP_FORCE; - - break; - - case ORT_ACC_PARALLEL: - case ORT_ACC_SERIAL: - rkind = ctx->region_type == ORT_ACC_PARALLEL ? "parallel" : "serial"; - - if (is_private) - flags |= GOVD_FIRSTPRIVATE; - else if (on_device || declared) - flags |= GOVD_MAP; - else if (AGGREGATE_TYPE_P (type)) - { - /* Aggregates default to 'present_or_copy', or 'present'. */ - if (ctx->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) - flags |= GOVD_MAP; - else - flags |= GOVD_MAP | GOVD_MAP_FORCE_PRESENT; - } - else - /* Scalars default to 'firstprivate'. */ - flags |= GOVD_FIRSTPRIVATE; - - break; - - default: - gcc_unreachable (); - } - - if (DECL_ARTIFICIAL (decl)) - ; /* We can get compiler-generated decls, and should not complain - about them. */ - else if (ctx->default_kind == OMP_CLAUSE_DEFAULT_NONE) - { - error ("%qE not specified in enclosing OpenACC %qs construct", - DECL_NAME (lang_hooks.decls.omp_report_decl (decl)), rkind); - inform (ctx->location, "enclosing OpenACC %qs construct", rkind); - } - else if (ctx->default_kind == OMP_CLAUSE_DEFAULT_PRESENT) - ; /* Handled above. */ - else - gcc_checking_assert (ctx->default_kind == OMP_CLAUSE_DEFAULT_SHARED); - - return flags; -} - -/* Record the fact that DECL was used within the OMP context CTX. - IN_CODE is true when real code uses DECL, and false when we should - merely emit default(none) errors. Return true if DECL is going to - be remapped and thus DECL shouldn't be gimplified into its - DECL_VALUE_EXPR (if any). */ - -static bool -omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) -{ - splay_tree_node n; - unsigned flags = in_code ? GOVD_SEEN : 0; - bool ret = false, shared; - - if (error_operand_p (decl)) - return false; - - if (ctx->region_type == ORT_NONE) - return lang_hooks.decls.omp_disregard_value_expr (decl, false); - - if (is_global_var (decl)) - { - /* Threadprivate variables are predetermined. */ - if (DECL_THREAD_LOCAL_P (decl)) - return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE); - - if (DECL_HAS_VALUE_EXPR_P (decl)) - { - if (ctx->region_type & ORT_ACC) - /* For OpenACC, defer expansion of value to avoid transfering - privatized common block data instead of im-/explicitly transfered - variables which are in common blocks. */ - ; - else - { - tree value = get_base_address (DECL_VALUE_EXPR (decl)); - - if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value)) - return omp_notice_threadprivate_variable (ctx, decl, value); - } - } - - if (gimplify_omp_ctxp->outer_context == NULL - && VAR_P (decl) - && oacc_get_fn_attrib (current_function_decl)) - { - location_t loc = DECL_SOURCE_LOCATION (decl); - - if (lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (decl))) - { - error_at (loc, - "%qE with %<link%> clause used in %<routine%> function", - DECL_NAME (decl)); - return false; - } - else if (!lookup_attribute ("omp declare target", - DECL_ATTRIBUTES (decl))) - { - error_at (loc, - "%qE requires a %<declare%> directive for use " - "in a %<routine%> function", DECL_NAME (decl)); - return false; - } - } - } - - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if ((ctx->region_type & ORT_TARGET) != 0) - { - if (ctx->region_type & ORT_ACC) - /* For OpenACC, as remarked above, defer expansion. */ - shared = false; - else - shared = true; - - ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); - if (n == NULL) - { - unsigned nflags = flags; - if ((ctx->region_type & ORT_ACC) == 0) - { - bool is_declare_target = false; - if (is_global_var (decl) - && varpool_node::get_create (decl)->offloadable) - { - struct gimplify_omp_ctx *octx; - for (octx = ctx->outer_context; - octx; octx = octx->outer_context) - { - n = splay_tree_lookup (octx->variables, - (splay_tree_key)decl); - if (n - && (n->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED - && (n->value & GOVD_DATA_SHARE_CLASS) != 0) - break; - } - is_declare_target = octx == NULL; - } - if (!is_declare_target) - { - int gdmk; - enum omp_clause_defaultmap_kind kind; - if (lang_hooks.decls.omp_allocatable_p (decl)) - gdmk = GDMK_ALLOCATABLE; - else if (lang_hooks.decls.omp_scalar_target_p (decl)) - gdmk = GDMK_SCALAR_TARGET; - else if (lang_hooks.decls.omp_scalar_p (decl, false)) - gdmk = GDMK_SCALAR; - else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE - || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) - == POINTER_TYPE))) - gdmk = GDMK_POINTER; - else - gdmk = GDMK_AGGREGATE; - kind = lang_hooks.decls.omp_predetermined_mapping (decl); - if (kind != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) - { - if (kind == OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE) - nflags |= GOVD_FIRSTPRIVATE; - else if (kind == OMP_CLAUSE_DEFAULTMAP_TO) - nflags |= GOVD_MAP | GOVD_MAP_TO_ONLY; - else - gcc_unreachable (); - } - else if (ctx->defaultmap[gdmk] == 0) - { - tree d = lang_hooks.decls.omp_report_decl (decl); - error ("%qE not specified in enclosing %<target%>", - DECL_NAME (d)); - inform (ctx->location, "enclosing %<target%>"); - } - else if (ctx->defaultmap[gdmk] - & (GOVD_MAP_0LEN_ARRAY | GOVD_FIRSTPRIVATE)) - nflags |= ctx->defaultmap[gdmk]; - else - { - gcc_assert (ctx->defaultmap[gdmk] & GOVD_MAP); - nflags |= ctx->defaultmap[gdmk] & ~GOVD_MAP; - } - } - } - - struct gimplify_omp_ctx *octx = ctx->outer_context; - if ((ctx->region_type & ORT_ACC) && octx) - { - /* Look in outer OpenACC contexts, to see if there's a - data attribute for this variable. */ - omp_notice_variable (octx, decl, in_code); - - for (; octx; octx = octx->outer_context) - { - if (!(octx->region_type & (ORT_TARGET_DATA | ORT_TARGET))) - break; - splay_tree_node n2 - = splay_tree_lookup (octx->variables, - (splay_tree_key) decl); - if (n2) - { - if (octx->region_type == ORT_ACC_HOST_DATA) - error ("variable %qE declared in enclosing " - "%<host_data%> region", DECL_NAME (decl)); - nflags |= GOVD_MAP; - if (octx->region_type == ORT_ACC_DATA - && (n2->value & GOVD_MAP_0LEN_ARRAY)) - nflags |= GOVD_MAP_0LEN_ARRAY; - goto found_outer; - } - } - } - - if ((nflags & ~(GOVD_MAP_TO_ONLY | GOVD_MAP_FROM_ONLY - | GOVD_MAP_ALLOC_ONLY)) == flags) - { - tree type = TREE_TYPE (decl); - - if (gimplify_omp_ctxp->target_firstprivatize_array_bases - && omp_privatize_by_reference (decl)) - type = TREE_TYPE (type); - if (!lang_hooks.types.omp_mappable_type (type)) - { - error ("%qD referenced in target region does not have " - "a mappable type", decl); - nflags |= GOVD_MAP | GOVD_EXPLICIT; - } - else - { - if ((ctx->region_type & ORT_ACC) != 0) - nflags = oacc_default_clause (ctx, decl, flags); - else - nflags |= GOVD_MAP; - } - } - found_outer: - omp_add_variable (ctx, decl, nflags); - } - else - { - /* If nothing changed, there's nothing left to do. */ - if ((n->value & flags) == flags) - return ret; - flags |= n->value; - n->value = flags; - } - goto do_outer; - } - - if (n == NULL) - { - if (ctx->region_type == ORT_WORKSHARE - || ctx->region_type == ORT_TASKGROUP - || ctx->region_type == ORT_SIMD - || ctx->region_type == ORT_ACC - || (ctx->region_type & ORT_TARGET_DATA) != 0) - goto do_outer; - - flags = omp_default_clause (ctx, decl, in_code, flags); - - if ((flags & GOVD_PRIVATE) - && lang_hooks.decls.omp_private_outer_ref (decl)) - flags |= GOVD_PRIVATE_OUTER_REF; - - omp_add_variable (ctx, decl, flags); - - shared = (flags & GOVD_SHARED) != 0; - ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); - goto do_outer; - } - - /* Don't mark as GOVD_SEEN addressable temporaries seen only in simd - lb, b or incr expressions, those shouldn't be turned into simd arrays. */ - if (ctx->region_type == ORT_SIMD - && ctx->in_for_exprs - && ((n->value & (GOVD_PRIVATE | GOVD_SEEN | GOVD_EXPLICIT)) - == GOVD_PRIVATE)) - flags &= ~GOVD_SEEN; - - if ((n->value & (GOVD_SEEN | GOVD_LOCAL)) == 0 - && (flags & (GOVD_SEEN | GOVD_LOCAL)) == GOVD_SEEN - && DECL_SIZE (decl)) - { - if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) - { - splay_tree_node n2; - tree t = DECL_VALUE_EXPR (decl); - gcc_assert (TREE_CODE (t) == INDIRECT_REF); - t = TREE_OPERAND (t, 0); - gcc_assert (DECL_P (t)); - n2 = splay_tree_lookup (ctx->variables, (splay_tree_key) t); - n2->value |= GOVD_SEEN; - } - else if (omp_privatize_by_reference (decl) - && TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl))) - && (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl)))) - != INTEGER_CST)) - { - splay_tree_node n2; - tree t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl))); - gcc_assert (DECL_P (t)); - n2 = splay_tree_lookup (ctx->variables, (splay_tree_key) t); - if (n2) - omp_notice_variable (ctx, t, true); - } - } - - if (ctx->region_type & ORT_ACC) - /* For OpenACC, as remarked above, defer expansion. */ - shared = false; - else - shared = ((flags | n->value) & GOVD_SHARED) != 0; - ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); - - /* If nothing changed, there's nothing left to do. */ - if ((n->value & flags) == flags) - return ret; - flags |= n->value; - n->value = flags; - - do_outer: - /* If the variable is private in the current context, then we don't - need to propagate anything to an outer context. */ - if ((flags & GOVD_PRIVATE) && !(flags & GOVD_PRIVATE_OUTER_REF)) - return ret; - if ((flags & (GOVD_LINEAR | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) - == (GOVD_LINEAR | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) - return ret; - if ((flags & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE - | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) - == (GOVD_LASTPRIVATE | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) - return ret; - if (ctx->outer_context - && omp_notice_variable (ctx->outer_context, decl, in_code)) - return true; - return ret; -} - -/* Verify that DECL is private within CTX. If there's specific information - to the contrary in the innermost scope, generate an error. */ - -static bool -omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, int simd) -{ - splay_tree_node n; - - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL) - { - if (n->value & GOVD_SHARED) - { - if (ctx == gimplify_omp_ctxp) - { - if (simd) - error ("iteration variable %qE is predetermined linear", - DECL_NAME (decl)); - else - error ("iteration variable %qE should be private", - DECL_NAME (decl)); - n->value = GOVD_PRIVATE; - return true; - } - else - return false; - } - else if ((n->value & GOVD_EXPLICIT) != 0 - && (ctx == gimplify_omp_ctxp - || (ctx->region_type == ORT_COMBINED_PARALLEL - && gimplify_omp_ctxp->outer_context == ctx))) - { - if ((n->value & GOVD_FIRSTPRIVATE) != 0) - error ("iteration variable %qE should not be firstprivate", - DECL_NAME (decl)); - else if ((n->value & GOVD_REDUCTION) != 0) - error ("iteration variable %qE should not be reduction", - DECL_NAME (decl)); - else if (simd != 1 && (n->value & GOVD_LINEAR) != 0) - error ("iteration variable %qE should not be linear", - DECL_NAME (decl)); - } - return (ctx == gimplify_omp_ctxp - || (ctx->region_type == ORT_COMBINED_PARALLEL - && gimplify_omp_ctxp->outer_context == ctx)); - } - - if (ctx->region_type != ORT_WORKSHARE - && ctx->region_type != ORT_TASKGROUP - && ctx->region_type != ORT_SIMD - && ctx->region_type != ORT_ACC) - return false; - else if (ctx->outer_context) - return omp_is_private (ctx->outer_context, decl, simd); - return false; -} - -/* Return true if DECL is private within a parallel region - that binds to the current construct's context or in parallel - region's REDUCTION clause. */ - -static bool -omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate) -{ - splay_tree_node n; - - do - { - ctx = ctx->outer_context; - if (ctx == NULL) - { - if (is_global_var (decl)) - return false; - - /* References might be private, but might be shared too, - when checking for copyprivate, assume they might be - private, otherwise assume they might be shared. */ - if (copyprivate) - return true; - - if (omp_privatize_by_reference (decl)) - return false; - - /* Treat C++ privatized non-static data members outside - of the privatization the same. */ - if (omp_member_access_dummy_var (decl)) - return false; - - return true; - } - - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - - if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 - && (n == NULL || (n->value & GOVD_DATA_SHARE_CLASS) == 0)) - { - if ((ctx->region_type & ORT_TARGET_DATA) != 0 - || n == NULL - || (n->value & GOVD_MAP) == 0) - continue; - return false; - } - - if (n != NULL) - { - if ((n->value & GOVD_LOCAL) != 0 - && omp_member_access_dummy_var (decl)) - return false; - return (n->value & GOVD_SHARED) == 0; - } - - if (ctx->region_type == ORT_WORKSHARE - || ctx->region_type == ORT_TASKGROUP - || ctx->region_type == ORT_SIMD - || ctx->region_type == ORT_ACC) - continue; - - break; - } - while (1); - return false; -} - -/* Callback for walk_tree to find a DECL_EXPR for the given DECL. */ - -static tree -find_decl_expr (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - - /* If this node has been visited, unmark it and keep looking. */ - if (TREE_CODE (t) == DECL_EXPR && DECL_EXPR_DECL (t) == (tree) data) - return t; - - if (IS_TYPE_OR_DECL_P (t)) - *walk_subtrees = 0; - return NULL_TREE; -} - - -/* Gimplify the affinity clause but effectively ignore it. - Generate: - var = begin; - if ((step > 1) ? var <= end : var > end) - locatator_var_expr; */ - -static void -gimplify_omp_affinity (tree *list_p, gimple_seq *pre_p) -{ - tree last_iter = NULL_TREE; - tree last_bind = NULL_TREE; - tree label = NULL_TREE; - tree *last_body = NULL; - for (tree c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) - { - tree t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) - { - if (TREE_VALUE (t) == null_pointer_node) - continue; - if (TREE_PURPOSE (t) != last_iter) - { - if (last_bind) - { - append_to_statement_list (label, last_body); - gimplify_and_add (last_bind, pre_p); - last_bind = NULL_TREE; - } - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - if (gimplify_expr (&TREE_VEC_ELT (it, 1), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || (gimplify_expr (&TREE_VEC_ELT (it, 4), pre_p, NULL, - is_gimple_val, fb_rvalue) - == GS_ERROR)) - return; - } - last_iter = TREE_PURPOSE (t); - tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 5); - last_bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), - NULL, block); - last_body = &BIND_EXPR_BODY (last_bind); - tree cond = NULL_TREE; - location_t loc = OMP_CLAUSE_LOCATION (c); - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - loc = DECL_SOURCE_LOCATION (var); - tree tem = build2_loc (loc, MODIFY_EXPR, void_type_node, - var, begin); - append_to_statement_list_force (tem, last_body); - - tree cond1 = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - step, build_zero_cst (TREE_TYPE (step))); - tree cond2 = fold_build2_loc (loc, LE_EXPR, boolean_type_node, - var, end); - tree cond3 = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - var, end); - cond1 = fold_build3_loc (loc, COND_EXPR, boolean_type_node, - cond1, cond2, cond3); - if (cond) - cond = fold_build2_loc (loc, TRUTH_AND_EXPR, - boolean_type_node, cond, cond1); - else - cond = cond1; - } - tree cont_label = create_artificial_label (loc); - label = build1 (LABEL_EXPR, void_type_node, cont_label); - tree tem = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, - void_node, - build_and_jump (&cont_label)); - append_to_statement_list_force (tem, last_body); - } - if (TREE_CODE (TREE_VALUE (t)) == COMPOUND_EXPR) - { - append_to_statement_list (TREE_OPERAND (TREE_VALUE (t), 0), - last_body); - TREE_VALUE (t) = TREE_OPERAND (TREE_VALUE (t), 1); - } - if (error_operand_p (TREE_VALUE (t))) - return; - append_to_statement_list_force (TREE_VALUE (t), last_body); - TREE_VALUE (t) = null_pointer_node; - } - else - { - if (last_bind) - { - append_to_statement_list (label, last_body); - gimplify_and_add (last_bind, pre_p); - last_bind = NULL_TREE; - } - if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) - { - gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, - NULL, is_gimple_val, fb_rvalue); - OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); - } - if (error_operand_p (OMP_CLAUSE_DECL (c))) - return; - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, - is_gimple_lvalue, fb_lvalue) == GS_ERROR) - return; - gimplify_and_add (OMP_CLAUSE_DECL (c), pre_p); - } - } - if (last_bind) - { - append_to_statement_list (label, last_body); - gimplify_and_add (last_bind, pre_p); - } - return; -} - -/* If *LIST_P contains any OpenMP depend clauses with iterators, - lower all the depend clauses by populating corresponding depend - array. Returns 0 if there are no such depend clauses, or - 2 if all depend clauses should be removed, 1 otherwise. */ - -static int -gimplify_omp_depend (tree *list_p, gimple_seq *pre_p) -{ - tree c; - gimple *g; - size_t n[4] = { 0, 0, 0, 0 }; - bool unused[4]; - tree counts[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; - tree last_iter = NULL_TREE, last_count = NULL_TREE; - size_t i, j; - location_t first_loc = UNKNOWN_LOCATION; - - for (c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) - { - switch (OMP_CLAUSE_DEPEND_KIND (c)) - { - case OMP_CLAUSE_DEPEND_IN: - i = 2; - break; - case OMP_CLAUSE_DEPEND_OUT: - case OMP_CLAUSE_DEPEND_INOUT: - i = 0; - break; - case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: - i = 1; - break; - case OMP_CLAUSE_DEPEND_DEPOBJ: - i = 3; - break; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - continue; - default: - gcc_unreachable (); - } - tree t = OMP_CLAUSE_DECL (c); - if (first_loc == UNKNOWN_LOCATION) - first_loc = OMP_CLAUSE_LOCATION (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) - { - if (TREE_PURPOSE (t) != last_iter) - { - tree tcnt = size_one_node; - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - if (gimplify_expr (&TREE_VEC_ELT (it, 1), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || (gimplify_expr (&TREE_VEC_ELT (it, 4), pre_p, NULL, - is_gimple_val, fb_rvalue) - == GS_ERROR)) - return 2; - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - tree orig_step = TREE_VEC_ELT (it, 4); - tree type = TREE_TYPE (var); - tree stype = TREE_TYPE (step); - location_t loc = DECL_SOURCE_LOCATION (var); - tree endmbegin; - /* Compute count for this iterator as - orig_step > 0 - ? (begin < end ? (end - begin + (step - 1)) / step : 0) - : (begin > end ? (end - begin + (step + 1)) / step : 0) - and compute product of those for the entire depend - clause. */ - if (POINTER_TYPE_P (type)) - endmbegin = fold_build2_loc (loc, POINTER_DIFF_EXPR, - stype, end, begin); - else - endmbegin = fold_build2_loc (loc, MINUS_EXPR, type, - end, begin); - tree stepm1 = fold_build2_loc (loc, MINUS_EXPR, stype, - step, - build_int_cst (stype, 1)); - tree stepp1 = fold_build2_loc (loc, PLUS_EXPR, stype, step, - build_int_cst (stype, 1)); - tree pos = fold_build2_loc (loc, PLUS_EXPR, stype, - unshare_expr (endmbegin), - stepm1); - pos = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, - pos, step); - tree neg = fold_build2_loc (loc, PLUS_EXPR, stype, - endmbegin, stepp1); - if (TYPE_UNSIGNED (stype)) - { - neg = fold_build1_loc (loc, NEGATE_EXPR, stype, neg); - step = fold_build1_loc (loc, NEGATE_EXPR, stype, step); - } - neg = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, - neg, step); - step = NULL_TREE; - tree cond = fold_build2_loc (loc, LT_EXPR, - boolean_type_node, - begin, end); - pos = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, - build_int_cst (stype, 0)); - cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, - end, begin); - neg = fold_build3_loc (loc, COND_EXPR, stype, cond, neg, - build_int_cst (stype, 0)); - tree osteptype = TREE_TYPE (orig_step); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - orig_step, - build_int_cst (osteptype, 0)); - tree cnt = fold_build3_loc (loc, COND_EXPR, stype, - cond, pos, neg); - cnt = fold_convert_loc (loc, sizetype, cnt); - if (gimplify_expr (&cnt, pre_p, NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) - return 2; - tcnt = size_binop_loc (loc, MULT_EXPR, tcnt, cnt); - } - if (gimplify_expr (&tcnt, pre_p, NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) - return 2; - last_iter = TREE_PURPOSE (t); - last_count = tcnt; - } - if (counts[i] == NULL_TREE) - counts[i] = last_count; - else - counts[i] = size_binop_loc (OMP_CLAUSE_LOCATION (c), - PLUS_EXPR, counts[i], last_count); - } - else - n[i]++; - } - for (i = 0; i < 4; i++) - if (counts[i]) - break; - if (i == 4) - return 0; - - tree total = size_zero_node; - for (i = 0; i < 4; i++) - { - unused[i] = counts[i] == NULL_TREE && n[i] == 0; - if (counts[i] == NULL_TREE) - counts[i] = size_zero_node; - if (n[i]) - counts[i] = size_binop (PLUS_EXPR, counts[i], size_int (n[i])); - if (gimplify_expr (&counts[i], pre_p, NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) - return 2; - total = size_binop (PLUS_EXPR, total, counts[i]); - } - - if (gimplify_expr (&total, pre_p, NULL, is_gimple_val, fb_rvalue) - == GS_ERROR) - return 2; - bool is_old = unused[1] && unused[3]; - tree totalpx = size_binop (PLUS_EXPR, unshare_expr (total), - size_int (is_old ? 1 : 4)); - tree type = build_array_type (ptr_type_node, build_index_type (totalpx)); - tree array = create_tmp_var_raw (type); - TREE_ADDRESSABLE (array) = 1; - if (!poly_int_tree_p (totalpx)) - { - if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (array))) - gimplify_type_sizes (TREE_TYPE (array), pre_p); - if (gimplify_omp_ctxp) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - while (ctx - && (ctx->region_type == ORT_WORKSHARE - || ctx->region_type == ORT_TASKGROUP - || ctx->region_type == ORT_SIMD - || ctx->region_type == ORT_ACC)) - ctx = ctx->outer_context; - if (ctx) - omp_add_variable (ctx, array, GOVD_LOCAL | GOVD_SEEN); - } - gimplify_vla_decl (array, pre_p); - } - else - gimple_add_tmp_var (array); - tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE, - NULL_TREE); - tree tem; - if (!is_old) - { - tem = build2 (MODIFY_EXPR, void_type_node, r, - build_int_cst (ptr_type_node, 0)); - gimplify_and_add (tem, pre_p); - r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, - NULL_TREE); - } - tem = build2 (MODIFY_EXPR, void_type_node, r, - fold_convert (ptr_type_node, total)); - gimplify_and_add (tem, pre_p); - for (i = 1; i < (is_old ? 2 : 4); i++) - { - r = build4 (ARRAY_REF, ptr_type_node, array, size_int (i + !is_old), - NULL_TREE, NULL_TREE); - tem = build2 (MODIFY_EXPR, void_type_node, r, counts[i - 1]); - gimplify_and_add (tem, pre_p); - } - - tree cnts[4]; - for (j = 4; j; j--) - if (!unused[j - 1]) - break; - for (i = 0; i < 4; i++) - { - if (i && (i >= j || unused[i - 1])) - { - cnts[i] = cnts[i - 1]; - continue; - } - cnts[i] = create_tmp_var (sizetype); - if (i == 0) - g = gimple_build_assign (cnts[i], size_int (is_old ? 2 : 5)); - else - { - tree t; - if (is_old) - t = size_binop (PLUS_EXPR, counts[0], size_int (2)); - else - t = size_binop (PLUS_EXPR, cnts[i - 1], counts[i - 1]); - if (gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue) - == GS_ERROR) - return 2; - g = gimple_build_assign (cnts[i], t); - } - gimple_seq_add_stmt (pre_p, g); - } - - last_iter = NULL_TREE; - tree last_bind = NULL_TREE; - tree *last_body = NULL; - for (c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) - { - switch (OMP_CLAUSE_DEPEND_KIND (c)) - { - case OMP_CLAUSE_DEPEND_IN: - i = 2; - break; - case OMP_CLAUSE_DEPEND_OUT: - case OMP_CLAUSE_DEPEND_INOUT: - i = 0; - break; - case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: - i = 1; - break; - case OMP_CLAUSE_DEPEND_DEPOBJ: - i = 3; - break; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - continue; - default: - gcc_unreachable (); - } - tree t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) - { - if (TREE_PURPOSE (t) != last_iter) - { - if (last_bind) - gimplify_and_add (last_bind, pre_p); - tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 5); - last_bind = build3 (BIND_EXPR, void_type_node, - BLOCK_VARS (block), NULL, block); - TREE_SIDE_EFFECTS (last_bind) = 1; - SET_EXPR_LOCATION (last_bind, OMP_CLAUSE_LOCATION (c)); - tree *p = &BIND_EXPR_BODY (last_bind); - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - tree orig_step = TREE_VEC_ELT (it, 4); - tree type = TREE_TYPE (var); - location_t loc = DECL_SOURCE_LOCATION (var); - /* Emit: - var = begin; - goto cond_label; - beg_label: - ... - var = var + step; - cond_label: - if (orig_step > 0) { - if (var < end) goto beg_label; - } else { - if (var > end) goto beg_label; - } - for each iterator, with inner iterators added to - the ... above. */ - tree beg_label = create_artificial_label (loc); - tree cond_label = NULL_TREE; - tem = build2_loc (loc, MODIFY_EXPR, void_type_node, - var, begin); - append_to_statement_list_force (tem, p); - tem = build_and_jump (&cond_label); - append_to_statement_list_force (tem, p); - tem = build1 (LABEL_EXPR, void_type_node, beg_label); - append_to_statement_list (tem, p); - tree bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, - NULL_TREE, NULL_TREE); - TREE_SIDE_EFFECTS (bind) = 1; - SET_EXPR_LOCATION (bind, loc); - append_to_statement_list_force (bind, p); - if (POINTER_TYPE_P (type)) - tem = build2_loc (loc, POINTER_PLUS_EXPR, type, - var, fold_convert_loc (loc, sizetype, - step)); - else - tem = build2_loc (loc, PLUS_EXPR, type, var, step); - tem = build2_loc (loc, MODIFY_EXPR, void_type_node, - var, tem); - append_to_statement_list_force (tem, p); - tem = build1 (LABEL_EXPR, void_type_node, cond_label); - append_to_statement_list (tem, p); - tree cond = fold_build2_loc (loc, LT_EXPR, - boolean_type_node, - var, end); - tree pos - = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, build_and_jump (&beg_label), - void_node); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - var, end); - tree neg - = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, build_and_jump (&beg_label), - void_node); - tree osteptype = TREE_TYPE (orig_step); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - orig_step, - build_int_cst (osteptype, 0)); - tem = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, pos, neg); - append_to_statement_list_force (tem, p); - p = &BIND_EXPR_BODY (bind); - } - last_body = p; - } - last_iter = TREE_PURPOSE (t); - if (TREE_CODE (TREE_VALUE (t)) == COMPOUND_EXPR) - { - append_to_statement_list (TREE_OPERAND (TREE_VALUE (t), - 0), last_body); - TREE_VALUE (t) = TREE_OPERAND (TREE_VALUE (t), 1); - } - if (error_operand_p (TREE_VALUE (t))) - return 2; - TREE_VALUE (t) = build_fold_addr_expr (TREE_VALUE (t)); - r = build4 (ARRAY_REF, ptr_type_node, array, cnts[i], - NULL_TREE, NULL_TREE); - tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, - void_type_node, r, TREE_VALUE (t)); - append_to_statement_list_force (tem, last_body); - tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, - void_type_node, cnts[i], - size_binop (PLUS_EXPR, cnts[i], size_int (1))); - append_to_statement_list_force (tem, last_body); - TREE_VALUE (t) = null_pointer_node; - } - else - { - if (last_bind) - { - gimplify_and_add (last_bind, pre_p); - last_bind = NULL_TREE; - } - if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) - { - gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, - NULL, is_gimple_val, fb_rvalue); - OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); - } - if (error_operand_p (OMP_CLAUSE_DECL (c))) - return 2; - OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c)); - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - return 2; - r = build4 (ARRAY_REF, ptr_type_node, array, cnts[i], - NULL_TREE, NULL_TREE); - tem = build2 (MODIFY_EXPR, void_type_node, r, OMP_CLAUSE_DECL (c)); - gimplify_and_add (tem, pre_p); - g = gimple_build_assign (cnts[i], size_binop (PLUS_EXPR, cnts[i], - size_int (1))); - gimple_seq_add_stmt (pre_p, g); - } - } - if (last_bind) - gimplify_and_add (last_bind, pre_p); - tree cond = boolean_false_node; - if (is_old) - { - if (!unused[0]) - cond = build2_loc (first_loc, NE_EXPR, boolean_type_node, cnts[0], - size_binop_loc (first_loc, PLUS_EXPR, counts[0], - size_int (2))); - if (!unused[2]) - cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, - build2_loc (first_loc, NE_EXPR, boolean_type_node, - cnts[2], - size_binop_loc (first_loc, PLUS_EXPR, - totalpx, - size_int (1)))); - } - else - { - tree prev = size_int (5); - for (i = 0; i < 4; i++) - { - if (unused[i]) - continue; - prev = size_binop_loc (first_loc, PLUS_EXPR, counts[i], prev); - cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, - build2_loc (first_loc, NE_EXPR, boolean_type_node, - cnts[i], unshare_expr (prev))); - } - } - tem = build3_loc (first_loc, COND_EXPR, void_type_node, cond, - build_call_expr_loc (first_loc, - builtin_decl_explicit (BUILT_IN_TRAP), - 0), void_node); - gimplify_and_add (tem, pre_p); - c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_LAST; - OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array); - OMP_CLAUSE_CHAIN (c) = *list_p; - *list_p = c; - return 1; -} - -/* Insert a GOMP_MAP_ALLOC or GOMP_MAP_RELEASE node following a - GOMP_MAP_STRUCT mapping. C is an always_pointer mapping. STRUCT_NODE is - the struct node to insert the new mapping after (when the struct node is - initially created). PREV_NODE is the first of two or three mappings for a - pointer, and is either: - - the node before C, when a pair of mappings is used, e.g. for a C/C++ - array section. - - not the node before C. This is true when we have a reference-to-pointer - type (with a mapping for the reference and for the pointer), or for - Fortran derived-type mappings with a GOMP_MAP_TO_PSET. - If SCP is non-null, the new node is inserted before *SCP. - if SCP is null, the new node is inserted before PREV_NODE. - The return type is: - - PREV_NODE, if SCP is non-null. - - The newly-created ALLOC or RELEASE node, if SCP is null. - - The second newly-created ALLOC or RELEASE node, if we are mapping a - reference to a pointer. */ - -static tree -insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, - tree prev_node, tree *scp) -{ - enum gomp_map_kind mkind - = (code == OMP_TARGET_EXIT_DATA || code == OACC_EXIT_DATA) - ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; - - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - tree cl = scp ? prev_node : c2; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = unshare_expr (OMP_CLAUSE_DECL (c)); - OMP_CLAUSE_CHAIN (c2) = scp ? *scp : prev_node; - if (OMP_CLAUSE_CHAIN (prev_node) != c - && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (prev_node)) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_TO_PSET)) - OMP_CLAUSE_SIZE (c2) = OMP_CLAUSE_SIZE (OMP_CLAUSE_CHAIN (prev_node)); - else - OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (ptr_type_node); - if (struct_node) - OMP_CLAUSE_CHAIN (struct_node) = c2; - - /* We might need to create an additional mapping if we have a reference to a - pointer (in C++). Don't do this if we have something other than a - GOMP_MAP_ALWAYS_POINTER though, i.e. a GOMP_MAP_TO_PSET. */ - if (OMP_CLAUSE_CHAIN (prev_node) != c - && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (prev_node)) == OMP_CLAUSE_MAP - && ((OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_ALWAYS_POINTER) - || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_ATTACH_DETACH))) - { - tree c4 = OMP_CLAUSE_CHAIN (prev_node); - tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c3, mkind); - OMP_CLAUSE_DECL (c3) = unshare_expr (OMP_CLAUSE_DECL (c4)); - OMP_CLAUSE_SIZE (c3) = TYPE_SIZE_UNIT (ptr_type_node); - OMP_CLAUSE_CHAIN (c3) = prev_node; - if (!scp) - OMP_CLAUSE_CHAIN (c2) = c3; - else - cl = c3; - } - - if (scp) - *scp = c2; - - return cl; -} - -/* Strip ARRAY_REFS or an indirect ref off BASE, find the containing object, - and set *BITPOSP and *POFFSETP to the bit offset of the access. - If BASE_REF is non-NULL and the containing object is a reference, set - *BASE_REF to that reference before dereferencing the object. - If BASE_REF is NULL, check that the containing object is a COMPONENT_REF or - has array type, else return NULL. */ - -static tree -extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, - poly_offset_int *poffsetp, tree *offsetp) -{ - tree offset; - poly_int64 bitsize, bitpos; - machine_mode mode; - int unsignedp, reversep, volatilep = 0; - poly_offset_int poffset; - - if (base_ref) - { - *base_ref = NULL_TREE; - - while (TREE_CODE (base) == ARRAY_REF) - base = TREE_OPERAND (base, 0); - - if (TREE_CODE (base) == INDIRECT_REF) - base = TREE_OPERAND (base, 0); - } - else - { - if (TREE_CODE (base) == ARRAY_REF) - { - while (TREE_CODE (base) == ARRAY_REF) - base = TREE_OPERAND (base, 0); - if (TREE_CODE (base) != COMPONENT_REF - || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE) - return NULL_TREE; - } - else if (TREE_CODE (base) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (base, 0)) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) - == REFERENCE_TYPE)) - base = TREE_OPERAND (base, 0); - } - - base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, - &unsignedp, &reversep, &volatilep); - - tree orig_base = base; - - if ((TREE_CODE (base) == INDIRECT_REF - || (TREE_CODE (base) == MEM_REF - && integer_zerop (TREE_OPERAND (base, 1)))) - && DECL_P (TREE_OPERAND (base, 0)) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) - base = TREE_OPERAND (base, 0); - - if (offset && poly_int_tree_p (offset)) - { - poffset = wi::to_poly_offset (offset); - offset = NULL_TREE; - } - else - poffset = 0; - - if (maybe_ne (bitpos, 0)) - poffset += bits_to_bytes_round_down (bitpos); - - *bitposp = bitpos; - *poffsetp = poffset; - *offsetp = offset; - - /* Set *BASE_REF if BASE was a dereferenced reference variable. */ - if (base_ref && orig_base != base) - *base_ref = orig_base; - - return base; -} - -/* Returns true if EXPR is or contains (as a sub-component) BASE_PTR. */ - -static bool -is_or_contains_p (tree expr, tree base_ptr) -{ - if ((TREE_CODE (expr) == INDIRECT_REF && TREE_CODE (base_ptr) == MEM_REF) - || (TREE_CODE (expr) == MEM_REF && TREE_CODE (base_ptr) == INDIRECT_REF)) - return operand_equal_p (TREE_OPERAND (expr, 0), - TREE_OPERAND (base_ptr, 0)); - while (!operand_equal_p (expr, base_ptr)) - { - if (TREE_CODE (base_ptr) == COMPOUND_EXPR) - base_ptr = TREE_OPERAND (base_ptr, 1); - if (TREE_CODE (base_ptr) == COMPONENT_REF - || TREE_CODE (base_ptr) == POINTER_PLUS_EXPR - || TREE_CODE (base_ptr) == SAVE_EXPR) - base_ptr = TREE_OPERAND (base_ptr, 0); - else - break; - } - return operand_equal_p (expr, base_ptr); -} - -/* Implement OpenMP 5.x map ordering rules for target directives. There are - several rules, and with some level of ambiguity, hopefully we can at least - collect the complexity here in one place. */ - -static void -omp_target_reorder_clauses (tree *list_p) -{ - /* Collect refs to alloc/release/delete maps. */ - auto_vec<tree, 32> ard; - tree *cp = list_p; - while (*cp != NULL_TREE) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ALLOC - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_RELEASE - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_DELETE)) - { - /* Unlink cp and push to ard. */ - tree c = *cp; - tree nc = OMP_CLAUSE_CHAIN (c); - *cp = nc; - ard.safe_push (c); - - /* Any associated pointer type maps should also move along. */ - while (*cp != NULL_TREE - && OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_FIRSTPRIVATE_REFERENCE - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_FIRSTPRIVATE_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ATTACH_DETACH - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_TO_PSET)) - { - c = *cp; - nc = OMP_CLAUSE_CHAIN (c); - *cp = nc; - ard.safe_push (c); - } - } - else - cp = &OMP_CLAUSE_CHAIN (*cp); - - /* Link alloc/release/delete maps to the end of list. */ - for (unsigned int i = 0; i < ard.length (); i++) - { - *cp = ard[i]; - cp = &OMP_CLAUSE_CHAIN (ard[i]); - } - *cp = NULL_TREE; - - /* OpenMP 5.0 requires that pointer variables are mapped before - its use as a base-pointer. */ - auto_vec<tree *, 32> atf; - for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP) - { - /* Collect alloc, to, from, to/from clause tree pointers. */ - gomp_map_kind k = OMP_CLAUSE_MAP_KIND (*cp); - if (k == GOMP_MAP_ALLOC - || k == GOMP_MAP_TO - || k == GOMP_MAP_FROM - || k == GOMP_MAP_TOFROM - || k == GOMP_MAP_ALWAYS_TO - || k == GOMP_MAP_ALWAYS_FROM - || k == GOMP_MAP_ALWAYS_TOFROM) - atf.safe_push (cp); - } - - for (unsigned int i = 0; i < atf.length (); i++) - if (atf[i]) - { - tree *cp = atf[i]; - tree decl = OMP_CLAUSE_DECL (*cp); - if (TREE_CODE (decl) == INDIRECT_REF || TREE_CODE (decl) == MEM_REF) - { - tree base_ptr = TREE_OPERAND (decl, 0); - STRIP_TYPE_NOPS (base_ptr); - for (unsigned int j = i + 1; j < atf.length (); j++) - if (atf[j]) - { - tree *cp2 = atf[j]; - tree decl2 = OMP_CLAUSE_DECL (*cp2); - - decl2 = OMP_CLAUSE_DECL (*cp2); - if (is_or_contains_p (decl2, base_ptr)) - { - /* Move *cp2 to before *cp. */ - tree c = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - - if (*cp2 != NULL_TREE - && OMP_CLAUSE_CODE (*cp2) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (*cp2) == GOMP_MAP_ALWAYS_POINTER) - { - tree c2 = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c2); - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; - } - - atf[j] = NULL; - } - } - } - } - - /* For attach_detach map clauses, if there is another map that maps the - attached/detached pointer, make sure that map is ordered before the - attach_detach. */ - atf.truncate (0); - for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP) - { - /* Collect alloc, to, from, to/from clauses, and - always_pointer/attach_detach clauses. */ - gomp_map_kind k = OMP_CLAUSE_MAP_KIND (*cp); - if (k == GOMP_MAP_ALLOC - || k == GOMP_MAP_TO - || k == GOMP_MAP_FROM - || k == GOMP_MAP_TOFROM - || k == GOMP_MAP_ALWAYS_TO - || k == GOMP_MAP_ALWAYS_FROM - || k == GOMP_MAP_ALWAYS_TOFROM - || k == GOMP_MAP_ATTACH_DETACH - || k == GOMP_MAP_ALWAYS_POINTER) - atf.safe_push (cp); - } - - for (unsigned int i = 0; i < atf.length (); i++) - if (atf[i]) - { - tree *cp = atf[i]; - tree ptr = OMP_CLAUSE_DECL (*cp); - STRIP_TYPE_NOPS (ptr); - if (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ATTACH_DETACH) - for (unsigned int j = i + 1; j < atf.length (); j++) - { - tree *cp2 = atf[j]; - tree decl2 = OMP_CLAUSE_DECL (*cp2); - if (OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ATTACH_DETACH - && OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ALWAYS_POINTER - && is_or_contains_p (decl2, ptr)) - { - /* Move *cp2 to before *cp. */ - tree c = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - atf[j] = NULL; - - /* If decl2 is of the form '*decl2_opnd0', and followed by an - ALWAYS_POINTER or ATTACH_DETACH of 'decl2_opnd0', move the - pointer operation along with *cp2. This can happen for C++ - reference sequences. */ - if (j + 1 < atf.length () - && (TREE_CODE (decl2) == INDIRECT_REF - || TREE_CODE (decl2) == MEM_REF)) - { - tree *cp3 = atf[j + 1]; - tree decl3 = OMP_CLAUSE_DECL (*cp3); - tree decl2_opnd0 = TREE_OPERAND (decl2, 0); - if ((OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ATTACH_DETACH) - && operand_equal_p (decl3, decl2_opnd0)) - { - /* Also move *cp3 to before *cp. */ - c = *cp3; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - atf[j + 1] = NULL; - j += 1; - } - } - } - } - } -} - -/* DECL is supposed to have lastprivate semantics in the outer contexts - of combined/composite constructs, starting with OCTX. - Add needed lastprivate, shared or map clause if no data sharing or - mapping clause are present. IMPLICIT_P is true if it is an implicit - clause (IV on simd), in which case the lastprivate will not be - copied to some constructs. */ - -static void -omp_lastprivate_for_combined_outer_constructs (struct gimplify_omp_ctx *octx, - tree decl, bool implicit_p) -{ - struct gimplify_omp_ctx *orig_octx = octx; - for (; octx; octx = octx->outer_context) - { - if ((octx->region_type == ORT_COMBINED_PARALLEL - || (octx->region_type & ORT_COMBINED_TEAMS) == ORT_COMBINED_TEAMS) - && splay_tree_lookup (octx->variables, - (splay_tree_key) decl) == NULL) - { - omp_add_variable (octx, decl, GOVD_SHARED | GOVD_SEEN); - continue; - } - if ((octx->region_type & ORT_TASK) != 0 - && octx->combined_loop - && splay_tree_lookup (octx->variables, - (splay_tree_key) decl) == NULL) - { - omp_add_variable (octx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); - continue; - } - if (implicit_p - && octx->region_type == ORT_WORKSHARE - && octx->combined_loop - && splay_tree_lookup (octx->variables, - (splay_tree_key) decl) == NULL - && octx->outer_context - && octx->outer_context->region_type == ORT_COMBINED_PARALLEL - && splay_tree_lookup (octx->outer_context->variables, - (splay_tree_key) decl) == NULL) - { - octx = octx->outer_context; - omp_add_variable (octx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); - continue; - } - if ((octx->region_type == ORT_WORKSHARE || octx->region_type == ORT_ACC) - && octx->combined_loop - && splay_tree_lookup (octx->variables, - (splay_tree_key) decl) == NULL - && !omp_check_private (octx, decl, false)) - { - omp_add_variable (octx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); - continue; - } - if (octx->region_type == ORT_COMBINED_TARGET) - { - splay_tree_node n = splay_tree_lookup (octx->variables, - (splay_tree_key) decl); - if (n == NULL) - { - omp_add_variable (octx, decl, GOVD_MAP | GOVD_SEEN); - octx = octx->outer_context; - } - else if (!implicit_p - && (n->value & GOVD_FIRSTPRIVATE_IMPLICIT)) - { - n->value &= ~(GOVD_FIRSTPRIVATE - | GOVD_FIRSTPRIVATE_IMPLICIT - | GOVD_EXPLICIT); - omp_add_variable (octx, decl, GOVD_MAP | GOVD_SEEN); - octx = octx->outer_context; - } - } - break; - } - if (octx && (implicit_p || octx != orig_octx)) - omp_notice_variable (octx, decl, true); -} - -/* Scan the OMP clauses in *LIST_P, installing mappings into a new - and previous omp contexts. */ - -static void -gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, - enum omp_region_type region_type, - enum tree_code code) -{ - struct gimplify_omp_ctx *ctx, *outer_ctx; - tree c; - hash_map<tree_operand_hash, tree> *struct_map_to_clause = NULL; - hash_map<tree_operand_hash, tree *> *struct_seen_clause = NULL; - hash_set<tree> *struct_deref_set = NULL; - tree *prev_list_p = NULL, *orig_list_p = list_p; - int handled_depend_iterators = -1; - int nowait = -1; - - ctx = new_omp_context (region_type); - ctx->code = code; - outer_ctx = ctx->outer_context; - if (code == OMP_TARGET) - { - if (!lang_GNU_Fortran ()) - ctx->defaultmap[GDMK_POINTER] = GOVD_MAP | GOVD_MAP_0LEN_ARRAY; - ctx->defaultmap[GDMK_SCALAR] = GOVD_FIRSTPRIVATE; - ctx->defaultmap[GDMK_SCALAR_TARGET] = (lang_GNU_Fortran () - ? GOVD_MAP : GOVD_FIRSTPRIVATE); - } - if (!lang_GNU_Fortran ()) - switch (code) - { - case OMP_TARGET: - case OMP_TARGET_DATA: - case OMP_TARGET_ENTER_DATA: - case OMP_TARGET_EXIT_DATA: - case OACC_DECLARE: - case OACC_HOST_DATA: - case OACC_PARALLEL: - case OACC_KERNELS: - ctx->target_firstprivatize_array_bases = true; - default: - break; - } - - if (code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - omp_target_reorder_clauses (list_p); - - while ((c = *list_p) != NULL) - { - bool remove = false; - bool notice_outer = true; - const char *check_non_private = NULL; - unsigned int flags; - tree decl; - - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_PRIVATE: - flags = GOVD_PRIVATE | GOVD_EXPLICIT; - if (lang_hooks.decls.omp_private_outer_ref (OMP_CLAUSE_DECL (c))) - { - flags |= GOVD_PRIVATE_OUTER_REF; - OMP_CLAUSE_PRIVATE_OUTER_REF (c) = 1; - } - else - notice_outer = false; - goto do_add; - case OMP_CLAUSE_SHARED: - flags = GOVD_SHARED | GOVD_EXPLICIT; - goto do_add; - case OMP_CLAUSE_FIRSTPRIVATE: - flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; - check_non_private = "firstprivate"; - if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c)) - { - gcc_assert (code == OMP_TARGET); - flags |= GOVD_FIRSTPRIVATE_IMPLICIT; - } - goto do_add; - case OMP_CLAUSE_LASTPRIVATE: - if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - switch (code) - { - case OMP_DISTRIBUTE: - error_at (OMP_CLAUSE_LOCATION (c), - "conditional %<lastprivate%> clause on " - "%qs construct", "distribute"); - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0; - break; - case OMP_TASKLOOP: - error_at (OMP_CLAUSE_LOCATION (c), - "conditional %<lastprivate%> clause on " - "%qs construct", "taskloop"); - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0; - break; - default: - break; - } - flags = GOVD_LASTPRIVATE | GOVD_SEEN | GOVD_EXPLICIT; - if (code != OMP_LOOP) - check_non_private = "lastprivate"; - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - goto do_add; - if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) - && !lang_hooks.decls.omp_scalar_p (decl, true)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "non-scalar variable %qD in conditional " - "%<lastprivate%> clause", decl); - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0; - } - if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - flags |= GOVD_LASTPRIVATE_CONDITIONAL; - omp_lastprivate_for_combined_outer_constructs (outer_ctx, decl, - false); - goto do_add; - case OMP_CLAUSE_REDUCTION: - if (OMP_CLAUSE_REDUCTION_TASK (c)) - { - if (region_type == ORT_WORKSHARE || code == OMP_SCOPE) - { - if (nowait == -1) - nowait = omp_find_clause (*list_p, - OMP_CLAUSE_NOWAIT) != NULL_TREE; - if (nowait - && (outer_ctx == NULL - || outer_ctx->region_type != ORT_COMBINED_PARALLEL)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<task%> reduction modifier on a construct " - "with a %<nowait%> clause"); - OMP_CLAUSE_REDUCTION_TASK (c) = 0; - } - } - else if ((region_type & ORT_PARALLEL) != ORT_PARALLEL) - { - error_at (OMP_CLAUSE_LOCATION (c), - "invalid %<task%> reduction modifier on construct " - "other than %<parallel%>, %qs, %<sections%> or " - "%<scope%>", lang_GNU_Fortran () ? "do" : "for"); - OMP_CLAUSE_REDUCTION_TASK (c) = 0; - } - } - if (OMP_CLAUSE_REDUCTION_INSCAN (c)) - switch (code) - { - case OMP_SECTIONS: - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "sections"); - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - break; - case OMP_PARALLEL: - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "parallel"); - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - break; - case OMP_TEAMS: - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "teams"); - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - break; - case OMP_TASKLOOP: - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "taskloop"); - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - break; - case OMP_SCOPE: - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "scope"); - OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; - break; - default: - break; - } - /* FALLTHRU */ - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; - /* OpenACC permits reductions on private variables. */ - if (!(region_type & ORT_ACC) - /* taskgroup is actually not a worksharing region. */ - && code != OMP_TASKGROUP) - check_non_private = omp_clause_code_name[OMP_CLAUSE_CODE (c)]; - decl = OMP_CLAUSE_DECL (c); - if (TREE_CODE (decl) == MEM_REF) - { - tree type = TREE_TYPE (decl); - bool saved_into_ssa = gimplify_ctxp->into_ssa; - gimplify_ctxp->into_ssa = false; - if (gimplify_expr (&TYPE_MAX_VALUE (TYPE_DOMAIN (type)), pre_p, - NULL, is_gimple_val, fb_rvalue, false) - == GS_ERROR) - { - gimplify_ctxp->into_ssa = saved_into_ssa; - remove = true; - break; - } - gimplify_ctxp->into_ssa = saved_into_ssa; - tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - if (DECL_P (v)) - { - omp_firstprivatize_variable (ctx, v); - omp_notice_variable (ctx, v, true); - } - decl = TREE_OPERAND (decl, 0); - if (TREE_CODE (decl) == POINTER_PLUS_EXPR) - { - gimplify_ctxp->into_ssa = false; - if (gimplify_expr (&TREE_OPERAND (decl, 1), pre_p, - NULL, is_gimple_val, fb_rvalue, false) - == GS_ERROR) - { - gimplify_ctxp->into_ssa = saved_into_ssa; - remove = true; - break; - } - gimplify_ctxp->into_ssa = saved_into_ssa; - v = TREE_OPERAND (decl, 1); - if (DECL_P (v)) - { - omp_firstprivatize_variable (ctx, v); - omp_notice_variable (ctx, v, true); - } - decl = TREE_OPERAND (decl, 0); - } - if (TREE_CODE (decl) == ADDR_EXPR - || TREE_CODE (decl) == INDIRECT_REF) - decl = TREE_OPERAND (decl, 0); - } - goto do_add_decl; - case OMP_CLAUSE_LINEAR: - if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - else - { - if (code == OMP_SIMD - && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) - { - struct gimplify_omp_ctx *octx = outer_ctx; - if (octx - && octx->region_type == ORT_WORKSHARE - && octx->combined_loop - && !octx->distribute) - { - if (octx->outer_context - && (octx->outer_context->region_type - == ORT_COMBINED_PARALLEL)) - octx = octx->outer_context->outer_context; - else - octx = octx->outer_context; - } - if (octx - && octx->region_type == ORT_WORKSHARE - && octx->combined_loop - && octx->distribute) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<linear%> clause for variable other than " - "loop iterator specified on construct " - "combined with %<distribute%>"); - remove = true; - break; - } - } - /* For combined #pragma omp parallel for simd, need to put - lastprivate and perhaps firstprivate too on the - parallel. Similarly for #pragma omp for simd. */ - struct gimplify_omp_ctx *octx = outer_ctx; - bool taskloop_seen = false; - decl = NULL_TREE; - do - { - if (OMP_CLAUSE_LINEAR_NO_COPYIN (c) - && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - break; - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - decl = NULL_TREE; - break; - } - flags = GOVD_SEEN; - if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) - flags |= GOVD_FIRSTPRIVATE; - if (!OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - flags |= GOVD_LASTPRIVATE; - if (octx - && octx->region_type == ORT_WORKSHARE - && octx->combined_loop) - { - if (octx->outer_context - && (octx->outer_context->region_type - == ORT_COMBINED_PARALLEL)) - octx = octx->outer_context; - else if (omp_check_private (octx, decl, false)) - break; - } - else if (octx - && (octx->region_type & ORT_TASK) != 0 - && octx->combined_loop) - taskloop_seen = true; - else if (octx - && octx->region_type == ORT_COMBINED_PARALLEL - && ((ctx->region_type == ORT_WORKSHARE - && octx == outer_ctx) - || taskloop_seen)) - flags = GOVD_SEEN | GOVD_SHARED; - else if (octx - && ((octx->region_type & ORT_COMBINED_TEAMS) - == ORT_COMBINED_TEAMS)) - flags = GOVD_SEEN | GOVD_SHARED; - else if (octx - && octx->region_type == ORT_COMBINED_TARGET) - { - if (flags & GOVD_LASTPRIVATE) - flags = GOVD_SEEN | GOVD_MAP; - } - else - break; - splay_tree_node on - = splay_tree_lookup (octx->variables, - (splay_tree_key) decl); - if (on && (on->value & GOVD_DATA_SHARE_CLASS) != 0) - { - octx = NULL; - break; - } - omp_add_variable (octx, decl, flags); - if (octx->outer_context == NULL) - break; - octx = octx->outer_context; - } - while (1); - if (octx - && decl - && (!OMP_CLAUSE_LINEAR_NO_COPYIN (c) - || !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) - omp_notice_variable (octx, decl, true); - } - flags = GOVD_LINEAR | GOVD_EXPLICIT; - if (OMP_CLAUSE_LINEAR_NO_COPYIN (c) - && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - { - notice_outer = false; - flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; - } - goto do_add; - - case OMP_CLAUSE_MAP: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - remove = true; - switch (code) - { - case OMP_TARGET: - break; - case OACC_DATA: - if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) - break; - /* FALLTHRU */ - case OMP_TARGET_DATA: - case OMP_TARGET_ENTER_DATA: - case OMP_TARGET_EXIT_DATA: - case OACC_ENTER_DATA: - case OACC_EXIT_DATA: - case OACC_HOST_DATA: - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER - || (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) - /* For target {,enter ,exit }data only the array slice is - mapped, but not the pointer to it. */ - remove = true; - break; - default: - break; - } - /* For Fortran, not only the pointer to the data is mapped but also - the address of the pointer, the array descriptor etc.; for - 'exit data' - and in particular for 'delete:' - having an 'alloc:' - does not make sense. Likewise, for 'update' only transferring the - data itself is needed as the rest has been handled in previous - directives. However, for 'exit data', the array descriptor needs - to be delete; hence, we turn the MAP_TO_PSET into a MAP_DELETE. - - NOTE: Generally, it is not safe to perform "enter data" operations - on arrays where the data *or the descriptor* may go out of scope - before a corresponding "exit data" operation -- and such a - descriptor may be synthesized temporarily, e.g. to pass an - explicit-shape array to a function expecting an assumed-shape - argument. Performing "enter data" inside the called function - would thus be problematic. */ - if (code == OMP_TARGET_EXIT_DATA - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_TO_PSET) - OMP_CLAUSE_SET_MAP_KIND (c, OMP_CLAUSE_MAP_KIND (*prev_list_p) - == GOMP_MAP_DELETE - ? GOMP_MAP_DELETE : GOMP_MAP_RELEASE); - else if ((code == OMP_TARGET_EXIT_DATA || code == OMP_TARGET_UPDATE) - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_TO_PSET)) - remove = true; - - if (remove) - break; - if (DECL_P (decl) && outer_ctx && (region_type & ORT_ACC)) - { - struct gimplify_omp_ctx *octx; - for (octx = outer_ctx; octx; octx = octx->outer_context) - { - if (octx->region_type != ORT_ACC_HOST_DATA) - break; - splay_tree_node n2 - = splay_tree_lookup (octx->variables, - (splay_tree_key) decl); - if (n2) - error_at (OMP_CLAUSE_LOCATION (c), "variable %qE " - "declared in enclosing %<host_data%> region", - DECL_NAME (decl)); - } - } - if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl) - : TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, - NULL, is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - else if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER - || (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_FIRSTPRIVATE_REFERENCE) - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST) - { - OMP_CLAUSE_SIZE (c) - = get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL, - false); - if ((region_type & ORT_TARGET) != 0) - omp_add_variable (ctx, OMP_CLAUSE_SIZE (c), - GOVD_FIRSTPRIVATE | GOVD_SEEN); - } - - if (TREE_CODE (decl) == TARGET_EXPR) - { - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, - is_gimple_lvalue, fb_lvalue) - == GS_ERROR) - remove = true; - } - else if (!DECL_P (decl)) - { - tree d = decl, *pd; - if (TREE_CODE (d) == ARRAY_REF) - { - while (TREE_CODE (d) == ARRAY_REF) - d = TREE_OPERAND (d, 0); - if (TREE_CODE (d) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (d)) == ARRAY_TYPE) - decl = d; - } - pd = &OMP_CLAUSE_DECL (c); - if (d == decl - && TREE_CODE (decl) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE) - && (OMP_CLAUSE_MAP_KIND (c) - != GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION)) - { - pd = &TREE_OPERAND (decl, 0); - decl = TREE_OPERAND (decl, 0); - } - bool indir_p = false; - bool component_ref_p = false; - tree indir_base = NULL_TREE; - tree orig_decl = decl; - tree decl_ref = NULL_TREE; - if ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) != 0 - && TREE_CODE (*pd) == COMPONENT_REF - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH - && code != OACC_UPDATE) - { - while (TREE_CODE (decl) == COMPONENT_REF) - { - decl = TREE_OPERAND (decl, 0); - component_ref_p = true; - if (((TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1))) - || INDIRECT_REF_P (decl)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == POINTER_TYPE)) - { - indir_p = true; - indir_base = decl; - decl = TREE_OPERAND (decl, 0); - STRIP_NOPS (decl); - } - if (TREE_CODE (decl) == INDIRECT_REF - && DECL_P (TREE_OPERAND (decl, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - { - decl_ref = decl; - decl = TREE_OPERAND (decl, 0); - } - } - } - else if (TREE_CODE (decl) == COMPONENT_REF - && (OMP_CLAUSE_MAP_KIND (c) - != GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION)) - { - component_ref_p = true; - while (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 0); - if (TREE_CODE (decl) == INDIRECT_REF - && DECL_P (TREE_OPERAND (decl, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - decl = TREE_OPERAND (decl, 0); - } - if (decl != orig_decl && DECL_P (decl) && indir_p) - { - gomp_map_kind k - = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - /* We have a dereference of a struct member. Make this an - attach/detach operation, and ensure the base pointer is - mapped as a FIRSTPRIVATE_POINTER. */ - OMP_CLAUSE_SET_MAP_KIND (c, k); - flags = GOVD_MAP | GOVD_SEEN | GOVD_EXPLICIT; - tree next_clause = OMP_CLAUSE_CHAIN (c); - if (k == GOMP_MAP_ATTACH - && code != OACC_ENTER_DATA - && code != OMP_TARGET_ENTER_DATA - && (!next_clause - || (OMP_CLAUSE_CODE (next_clause) != OMP_CLAUSE_MAP) - || (OMP_CLAUSE_MAP_KIND (next_clause) - != GOMP_MAP_POINTER) - || OMP_CLAUSE_DECL (next_clause) != decl) - && (!struct_deref_set - || !struct_deref_set->contains (decl)) - && (!struct_map_to_clause - || !struct_map_to_clause->get (indir_base))) - { - if (!struct_deref_set) - struct_deref_set = new hash_set<tree> (); - /* As well as the attach, we also need a - FIRSTPRIVATE_POINTER clause to properly map the - pointer to the struct base. */ - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALLOC); - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c2) - = 1; - tree charptr_zero - = build_int_cst (build_pointer_type (char_type_node), - 0); - OMP_CLAUSE_DECL (c2) - = build2 (MEM_REF, char_type_node, - decl_ref ? decl_ref : decl, charptr_zero); - OMP_CLAUSE_SIZE (c2) = size_zero_node; - tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c3, - GOMP_MAP_FIRSTPRIVATE_POINTER); - OMP_CLAUSE_DECL (c3) = decl; - OMP_CLAUSE_SIZE (c3) = size_zero_node; - tree mapgrp = *prev_list_p; - *prev_list_p = c2; - OMP_CLAUSE_CHAIN (c3) = mapgrp; - OMP_CLAUSE_CHAIN (c2) = c3; - - struct_deref_set->add (decl); - } - goto do_add_decl; - } - /* An "attach/detach" operation on an update directive should - behave as a GOMP_MAP_ALWAYS_POINTER. Beware that - unlike attach or detach map kinds, GOMP_MAP_ALWAYS_POINTER - depends on the previous mapping. */ - if (code == OACC_UPDATE - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_POINTER); - if ((DECL_P (decl) - || (component_ref_p - && (INDIRECT_REF_P (decl) - || TREE_CODE (decl) == MEM_REF - || TREE_CODE (decl) == ARRAY_REF))) - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH - && code != OACC_UPDATE - && code != OMP_TARGET_UPDATE) - { - if (error_operand_p (decl)) - { - remove = true; - break; - } - - tree stype = TREE_TYPE (decl); - if (TREE_CODE (stype) == REFERENCE_TYPE) - stype = TREE_TYPE (stype); - if (TYPE_SIZE_UNIT (stype) == NULL - || TREE_CODE (TYPE_SIZE_UNIT (stype)) != INTEGER_CST) - { - error_at (OMP_CLAUSE_LOCATION (c), - "mapping field %qE of variable length " - "structure", OMP_CLAUSE_DECL (c)); - remove = true; - break; - } - - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - { - /* Error recovery. */ - if (prev_list_p == NULL) - { - remove = true; - break; - } - - /* The below prev_list_p based error recovery code is - currently no longer valid for OpenMP. */ - if (code != OMP_TARGET - && code != OMP_TARGET_DATA - && code != OMP_TARGET_UPDATE - && code != OMP_TARGET_ENTER_DATA - && code != OMP_TARGET_EXIT_DATA - && OMP_CLAUSE_CHAIN (*prev_list_p) != c) - { - tree ch = OMP_CLAUSE_CHAIN (*prev_list_p); - if (ch == NULL_TREE || OMP_CLAUSE_CHAIN (ch) != c) - { - remove = true; - break; - } - } - } - - poly_offset_int offset1; - poly_int64 bitpos1; - tree tree_offset1; - tree base_ref; - - tree base - = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ref, - &bitpos1, &offset1, - &tree_offset1); - - bool do_map_struct = (base == decl && !tree_offset1); - - splay_tree_node n - = (DECL_P (decl) - ? splay_tree_lookup (ctx->variables, - (splay_tree_key) decl) - : NULL); - bool ptr = (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_ALWAYS_POINTER); - bool attach_detach = (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_ATTACH_DETACH); - bool attach = OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH; - bool has_attachments = false; - /* For OpenACC, pointers in structs should trigger an - attach action. */ - if (attach_detach - && ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA)) - - { - /* Turn a GOMP_MAP_ATTACH_DETACH clause into a - GOMP_MAP_ATTACH or GOMP_MAP_DETACH clause after we - have detected a case that needs a GOMP_MAP_STRUCT - mapping added. */ - gomp_map_kind k - = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, k); - has_attachments = true; - } - - /* We currently don't handle non-constant offset accesses wrt to - GOMP_MAP_STRUCT elements. */ - if (!do_map_struct) - goto skip_map_struct; - - /* Nor for attach_detach for OpenMP. */ - if ((code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_UPDATE - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && attach_detach) - { - if (DECL_P (decl)) - { - if (struct_seen_clause == NULL) - struct_seen_clause - = new hash_map<tree_operand_hash, tree *>; - if (!struct_seen_clause->get (decl)) - struct_seen_clause->put (decl, list_p); - } - - goto skip_map_struct; - } - - if ((DECL_P (decl) - && (n == NULL || (n->value & GOVD_MAP) == 0)) - || (!DECL_P (decl) - && (!struct_map_to_clause - || struct_map_to_clause->get (decl) == NULL))) - { - tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT - : GOMP_MAP_STRUCT; - - OMP_CLAUSE_SET_MAP_KIND (l, k); - if (base_ref) - OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); - else - { - OMP_CLAUSE_DECL (l) = unshare_expr (decl); - if (!DECL_P (OMP_CLAUSE_DECL (l)) - && (gimplify_expr (&OMP_CLAUSE_DECL (l), - pre_p, NULL, is_gimple_lvalue, - fb_lvalue) - == GS_ERROR)) - { - remove = true; - break; - } - } - OMP_CLAUSE_SIZE (l) - = (!attach - ? size_int (1) - : DECL_P (OMP_CLAUSE_DECL (l)) - ? DECL_SIZE_UNIT (OMP_CLAUSE_DECL (l)) - : TYPE_SIZE_UNIT (TREE_TYPE (OMP_CLAUSE_DECL (l)))); - if (struct_map_to_clause == NULL) - struct_map_to_clause - = new hash_map<tree_operand_hash, tree>; - struct_map_to_clause->put (decl, l); - if (ptr || attach_detach) - { - tree **sc = (struct_seen_clause - ? struct_seen_clause->get (decl) - : NULL); - tree *insert_node_pos = sc ? *sc : prev_list_p; - - insert_struct_comp_map (code, c, l, *insert_node_pos, - NULL); - *insert_node_pos = l; - prev_list_p = NULL; - } - else - { - OMP_CLAUSE_CHAIN (l) = c; - *list_p = l; - list_p = &OMP_CLAUSE_CHAIN (l); - } - if (base_ref && code == OMP_TARGET) - { - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - enum gomp_map_kind mkind - = GOMP_MAP_FIRSTPRIVATE_REFERENCE; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); - OMP_CLAUSE_CHAIN (l) = c2; - } - flags = GOVD_MAP | GOVD_EXPLICIT; - if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) - || ptr - || attach_detach) - flags |= GOVD_SEEN; - if (has_attachments) - flags |= GOVD_MAP_HAS_ATTACHMENTS; - - /* If this is a *pointer-to-struct expression, make sure a - firstprivate map of the base-pointer exists. */ - if (component_ref_p - && ((TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1))) - || INDIRECT_REF_P (decl)) - && DECL_P (TREE_OPERAND (decl, 0)) - && !splay_tree_lookup (ctx->variables, - ((splay_tree_key) - TREE_OPERAND (decl, 0)))) - { - decl = TREE_OPERAND (decl, 0); - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - enum gomp_map_kind mkind - = GOMP_MAP_FIRSTPRIVATE_POINTER; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; - } - - if (DECL_P (decl)) - goto do_add_decl; - } - else if (struct_map_to_clause) - { - tree *osc = struct_map_to_clause->get (decl); - tree *sc = NULL, *scp = NULL; - if (n != NULL - && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) - || ptr - || attach_detach)) - n->value |= GOVD_SEEN; - sc = &OMP_CLAUSE_CHAIN (*osc); - if (*sc != c - && (OMP_CLAUSE_MAP_KIND (*sc) - == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) - sc = &OMP_CLAUSE_CHAIN (*sc); - /* Here "prev_list_p" is the end of the inserted - alloc/release nodes after the struct node, OSC. */ - for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) - if ((ptr || attach_detach) && sc == prev_list_p) - break; - else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != COMPONENT_REF - && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != INDIRECT_REF) - && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != ARRAY_REF)) - break; - else - { - tree sc_decl = OMP_CLAUSE_DECL (*sc); - poly_offset_int offsetn; - poly_int64 bitposn; - tree tree_offsetn; - tree base - = extract_base_bit_offset (sc_decl, NULL, - &bitposn, &offsetn, - &tree_offsetn); - if (base != decl) - break; - if (scp) - continue; - if ((region_type & ORT_ACC) != 0) - { - /* This duplicate checking code is currently only - enabled for OpenACC. */ - tree d1 = OMP_CLAUSE_DECL (*sc); - tree d2 = OMP_CLAUSE_DECL (c); - while (TREE_CODE (d1) == ARRAY_REF) - d1 = TREE_OPERAND (d1, 0); - while (TREE_CODE (d2) == ARRAY_REF) - d2 = TREE_OPERAND (d2, 0); - if (TREE_CODE (d1) == INDIRECT_REF) - d1 = TREE_OPERAND (d1, 0); - if (TREE_CODE (d2) == INDIRECT_REF) - d2 = TREE_OPERAND (d2, 0); - while (TREE_CODE (d1) == COMPONENT_REF) - if (TREE_CODE (d2) == COMPONENT_REF - && TREE_OPERAND (d1, 1) - == TREE_OPERAND (d2, 1)) - { - d1 = TREE_OPERAND (d1, 0); - d2 = TREE_OPERAND (d2, 0); - } - else - break; - if (d1 == d2) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in map " - "clauses", OMP_CLAUSE_DECL (c)); - remove = true; - break; - } - } - if (maybe_lt (offset1, offsetn) - || (known_eq (offset1, offsetn) - && maybe_lt (bitpos1, bitposn))) - { - if (ptr || attach_detach) - scp = sc; - else - break; - } - } - if (remove) - break; - if (!attach) - OMP_CLAUSE_SIZE (*osc) - = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), - size_one_node); - if (ptr || attach_detach) - { - tree cl = insert_struct_comp_map (code, c, NULL, - *prev_list_p, scp); - if (sc == prev_list_p) - { - *sc = cl; - prev_list_p = NULL; - } - else - { - *prev_list_p = OMP_CLAUSE_CHAIN (c); - list_p = prev_list_p; - prev_list_p = NULL; - OMP_CLAUSE_CHAIN (c) = *sc; - *sc = cl; - continue; - } - } - else if (*sc != c) - { - if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, - fb_lvalue) - == GS_ERROR) - { - remove = true; - break; - } - *list_p = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *sc; - *sc = c; - continue; - } - } - skip_map_struct: - ; - } - else if ((code == OACC_ENTER_DATA - || code == OACC_EXIT_DATA - || code == OACC_DATA - || code == OACC_PARALLEL - || code == OACC_KERNELS - || code == OACC_SERIAL - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - { - gomp_map_kind k = ((code == OACC_EXIT_DATA - || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, k); - } - - if (code == OMP_TARGET && OMP_CLAUSE_MAP_IN_REDUCTION (c)) - { - /* Don't gimplify *pd fully at this point, as the base - will need to be adjusted during omp lowering. */ - auto_vec<tree, 10> expr_stack; - tree *p = pd; - while (handled_component_p (*p) - || TREE_CODE (*p) == INDIRECT_REF - || TREE_CODE (*p) == ADDR_EXPR - || TREE_CODE (*p) == MEM_REF - || TREE_CODE (*p) == NON_LVALUE_EXPR) - { - expr_stack.safe_push (*p); - p = &TREE_OPERAND (*p, 0); - } - for (int i = expr_stack.length () - 1; i >= 0; i--) - { - tree t = expr_stack[i]; - if (TREE_CODE (t) == ARRAY_REF - || TREE_CODE (t) == ARRAY_RANGE_REF) - { - if (TREE_OPERAND (t, 2) == NULL_TREE) - { - tree low = unshare_expr (array_ref_low_bound (t)); - if (!is_gimple_min_invariant (low)) - { - TREE_OPERAND (t, 2) = low; - if (gimplify_expr (&TREE_OPERAND (t, 2), - pre_p, NULL, - is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - } - } - else if (gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - NULL, is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - if (TREE_OPERAND (t, 3) == NULL_TREE) - { - tree elmt_size = array_ref_element_size (t); - if (!is_gimple_min_invariant (elmt_size)) - { - elmt_size = unshare_expr (elmt_size); - tree elmt_type - = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, - 0))); - tree factor - = size_int (TYPE_ALIGN_UNIT (elmt_type)); - elmt_size - = size_binop (EXACT_DIV_EXPR, elmt_size, - factor); - TREE_OPERAND (t, 3) = elmt_size; - if (gimplify_expr (&TREE_OPERAND (t, 3), - pre_p, NULL, - is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - } - } - else if (gimplify_expr (&TREE_OPERAND (t, 3), pre_p, - NULL, is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - } - else if (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_OPERAND (t, 2) == NULL_TREE) - { - tree offset = component_ref_field_offset (t); - if (!is_gimple_min_invariant (offset)) - { - offset = unshare_expr (offset); - tree field = TREE_OPERAND (t, 1); - tree factor - = size_int (DECL_OFFSET_ALIGN (field) - / BITS_PER_UNIT); - offset = size_binop (EXACT_DIV_EXPR, offset, - factor); - TREE_OPERAND (t, 2) = offset; - if (gimplify_expr (&TREE_OPERAND (t, 2), - pre_p, NULL, - is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - } - } - else if (gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - NULL, is_gimple_reg, - fb_rvalue) == GS_ERROR) - remove = true; - } - } - for (; expr_stack.length () > 0; ) - { - tree t = expr_stack.pop (); - - if (TREE_CODE (t) == ARRAY_REF - || TREE_CODE (t) == ARRAY_RANGE_REF) - { - if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)) - && gimplify_expr (&TREE_OPERAND (t, 1), pre_p, - NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) - remove = true; - } - } - } - else if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, - fb_lvalue) == GS_ERROR) - { - remove = true; - break; - } - - /* If this was of the form map(*pointer_to_struct), then the - 'pointer_to_struct' DECL should be considered deref'ed. */ - if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALLOC - || GOMP_MAP_COPY_TO_P (OMP_CLAUSE_MAP_KIND (c)) - || GOMP_MAP_COPY_FROM_P (OMP_CLAUSE_MAP_KIND (c))) - && INDIRECT_REF_P (orig_decl) - && DECL_P (TREE_OPERAND (orig_decl, 0)) - && TREE_CODE (TREE_TYPE (orig_decl)) == RECORD_TYPE) - { - tree ptr = TREE_OPERAND (orig_decl, 0); - if (!struct_deref_set || !struct_deref_set->contains (ptr)) - { - if (!struct_deref_set) - struct_deref_set = new hash_set<tree> (); - struct_deref_set->add (ptr); - } - } - - if (!remove - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_POINTER - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH_DETACH - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET - && OMP_CLAUSE_CHAIN (c) - && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c)) == OMP_CLAUSE_MAP - && ((OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) - == GOMP_MAP_ALWAYS_POINTER) - || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) - == GOMP_MAP_ATTACH_DETACH) - || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) - == GOMP_MAP_TO_PSET))) - prev_list_p = list_p; - - break; - } - else - { - /* DECL_P (decl) == true */ - tree *sc; - if (struct_map_to_clause - && (sc = struct_map_to_clause->get (decl)) != NULL - && OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_STRUCT - && decl == OMP_CLAUSE_DECL (*sc)) - { - /* We have found a map of the whole structure after a - leading GOMP_MAP_STRUCT has been created, so refill the - leading clause into a map of the whole structure - variable, and remove the current one. - TODO: we should be able to remove some maps of the - following structure element maps if they are of - compatible TO/FROM/ALLOC type. */ - OMP_CLAUSE_SET_MAP_KIND (*sc, OMP_CLAUSE_MAP_KIND (c)); - OMP_CLAUSE_SIZE (*sc) = unshare_expr (OMP_CLAUSE_SIZE (c)); - remove = true; - break; - } - } - flags = GOVD_MAP | GOVD_EXPLICIT; - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TO - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TOFROM) - flags |= GOVD_MAP_ALWAYS_TO; - - if ((code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - { - for (struct gimplify_omp_ctx *octx = outer_ctx; octx; - octx = octx->outer_context) - { - splay_tree_node n - = splay_tree_lookup (octx->variables, - (splay_tree_key) OMP_CLAUSE_DECL (c)); - /* If this is contained in an outer OpenMP region as a - firstprivate value, remove the attach/detach. */ - if (n && (n->value & GOVD_FIRSTPRIVATE)) - { - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FIRSTPRIVATE_POINTER); - goto do_add; - } - } - - enum gomp_map_kind map_kind = (code == OMP_TARGET_EXIT_DATA - ? GOMP_MAP_DETACH - : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, map_kind); - } - - goto do_add; - - case OMP_CLAUSE_AFFINITY: - gimplify_omp_affinity (list_p, pre_p); - remove = true; - break; - case OMP_CLAUSE_DEPEND: - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) - { - tree deps = OMP_CLAUSE_DECL (c); - while (deps && TREE_CODE (deps) == TREE_LIST) - { - if (TREE_CODE (TREE_PURPOSE (deps)) == TRUNC_DIV_EXPR - && DECL_P (TREE_OPERAND (TREE_PURPOSE (deps), 1))) - gimplify_expr (&TREE_OPERAND (TREE_PURPOSE (deps), 1), - pre_p, NULL, is_gimple_val, fb_rvalue); - deps = TREE_CHAIN (deps); - } - break; - } - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) - break; - if (handled_depend_iterators == -1) - handled_depend_iterators = gimplify_omp_depend (list_p, pre_p); - if (handled_depend_iterators) - { - if (handled_depend_iterators == 2) - remove = true; - break; - } - if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) - { - gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, - NULL, is_gimple_val, fb_rvalue); - OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); - } - if (error_operand_p (OMP_CLAUSE_DECL (c))) - { - remove = true; - break; - } - OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c)); - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - if (code == OMP_TASK) - ctx->has_depend = true; - break; - - case OMP_CLAUSE_TO: - case OMP_CLAUSE_FROM: - case OMP_CLAUSE__CACHE_: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - remove = true; - break; - } - if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl) - : TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, - NULL, is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - if (!DECL_P (decl)) - { - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, - NULL, is_gimple_lvalue, fb_lvalue) - == GS_ERROR) - { - remove = true; - break; - } - break; - } - goto do_notice; - - case OMP_CLAUSE_USE_DEVICE_PTR: - case OMP_CLAUSE_USE_DEVICE_ADDR: - flags = GOVD_EXPLICIT; - goto do_add; - - case OMP_CLAUSE_IS_DEVICE_PTR: - flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; - goto do_add; - - do_add: - decl = OMP_CLAUSE_DECL (c); - do_add_decl: - if (error_operand_p (decl)) - { - remove = true; - break; - } - if (DECL_NAME (decl) == NULL_TREE && (flags & GOVD_SHARED) == 0) - { - tree t = omp_member_access_dummy_var (decl); - if (t) - { - tree v = DECL_VALUE_EXPR (decl); - DECL_NAME (decl) = DECL_NAME (TREE_OPERAND (v, 1)); - if (outer_ctx) - omp_notice_variable (outer_ctx, t, true); - } - } - if (code == OACC_DATA - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) - flags |= GOVD_MAP_0LEN_ARRAY; - omp_add_variable (ctx, decl, flags); - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) - && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) - { - struct gimplify_omp_ctx *pctx - = code == OMP_TARGET ? outer_ctx : ctx; - if (pctx) - omp_add_variable (pctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c), - GOVD_LOCAL | GOVD_SEEN); - if (pctx - && OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) - && walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), - find_decl_expr, - OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), - NULL) == NULL_TREE) - omp_add_variable (pctx, - OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), - GOVD_LOCAL | GOVD_SEEN); - gimplify_omp_ctxp = pctx; - push_gimplify_context (); - - OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL; - OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL; - - gimplify_and_add (OMP_CLAUSE_REDUCTION_INIT (c), - &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c)); - pop_gimplify_context - (gimple_seq_first_stmt (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))); - push_gimplify_context (); - gimplify_and_add (OMP_CLAUSE_REDUCTION_MERGE (c), - &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c)); - pop_gimplify_context - (gimple_seq_first_stmt (OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c))); - OMP_CLAUSE_REDUCTION_INIT (c) = NULL_TREE; - OMP_CLAUSE_REDUCTION_MERGE (c) = NULL_TREE; - - gimplify_omp_ctxp = outer_ctx; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_STMT (c)) - { - gimplify_omp_ctxp = ctx; - push_gimplify_context (); - if (TREE_CODE (OMP_CLAUSE_LASTPRIVATE_STMT (c)) != BIND_EXPR) - { - tree bind = build3 (BIND_EXPR, void_type_node, NULL, - NULL, NULL); - TREE_SIDE_EFFECTS (bind) = 1; - BIND_EXPR_BODY (bind) = OMP_CLAUSE_LASTPRIVATE_STMT (c); - OMP_CLAUSE_LASTPRIVATE_STMT (c) = bind; - } - gimplify_and_add (OMP_CLAUSE_LASTPRIVATE_STMT (c), - &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); - pop_gimplify_context - (gimple_seq_first_stmt (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))); - OMP_CLAUSE_LASTPRIVATE_STMT (c) = NULL_TREE; - - gimplify_omp_ctxp = outer_ctx; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && OMP_CLAUSE_LINEAR_STMT (c)) - { - gimplify_omp_ctxp = ctx; - push_gimplify_context (); - if (TREE_CODE (OMP_CLAUSE_LINEAR_STMT (c)) != BIND_EXPR) - { - tree bind = build3 (BIND_EXPR, void_type_node, NULL, - NULL, NULL); - TREE_SIDE_EFFECTS (bind) = 1; - BIND_EXPR_BODY (bind) = OMP_CLAUSE_LINEAR_STMT (c); - OMP_CLAUSE_LINEAR_STMT (c) = bind; - } - gimplify_and_add (OMP_CLAUSE_LINEAR_STMT (c), - &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)); - pop_gimplify_context - (gimple_seq_first_stmt (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))); - OMP_CLAUSE_LINEAR_STMT (c) = NULL_TREE; - - gimplify_omp_ctxp = outer_ctx; - } - if (notice_outer) - goto do_notice; - break; - - case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_COPYPRIVATE: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - remove = true; - break; - } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_COPYPRIVATE - && !remove - && !omp_check_private (ctx, decl, true)) - { - remove = true; - if (is_global_var (decl)) - { - if (DECL_THREAD_LOCAL_P (decl)) - remove = false; - else if (DECL_HAS_VALUE_EXPR_P (decl)) - { - tree value = get_base_address (DECL_VALUE_EXPR (decl)); - - if (value - && DECL_P (value) - && DECL_THREAD_LOCAL_P (value)) - remove = false; - } - } - if (remove) - error_at (OMP_CLAUSE_LOCATION (c), - "copyprivate variable %qE is not threadprivate" - " or private in outer context", DECL_NAME (decl)); - } - do_notice: - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && outer_ctx - && ((region_type & ORT_TASKLOOP) == ORT_TASKLOOP - || (region_type == ORT_WORKSHARE - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && (OMP_CLAUSE_REDUCTION_INSCAN (c) - || code == OMP_LOOP))) - && (outer_ctx->region_type == ORT_COMBINED_PARALLEL - || (code == OMP_LOOP - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && ((outer_ctx->region_type & ORT_COMBINED_TEAMS) - == ORT_COMBINED_TEAMS)))) - { - splay_tree_node on - = splay_tree_lookup (outer_ctx->variables, - (splay_tree_key)decl); - if (on == NULL || (on->value & GOVD_DATA_SHARE_CLASS) == 0) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF - && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE - || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) - == POINTER_TYPE)))) - omp_firstprivatize_variable (outer_ctx, decl); - else - { - omp_add_variable (outer_ctx, decl, - GOVD_SEEN | GOVD_SHARED); - if (outer_ctx->outer_context) - omp_notice_variable (outer_ctx->outer_context, decl, - true); - } - } - } - if (outer_ctx) - omp_notice_variable (outer_ctx, decl, true); - if (check_non_private - && (region_type == ORT_WORKSHARE || code == OMP_SCOPE) - && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION - || decl == OMP_CLAUSE_DECL (c) - || (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF - && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) - == ADDR_EXPR - || (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) - == POINTER_PLUS_EXPR - && (TREE_CODE (TREE_OPERAND (TREE_OPERAND - (OMP_CLAUSE_DECL (c), 0), 0)) - == ADDR_EXPR))))) - && omp_check_private (ctx, decl, false)) - { - error ("%s variable %qE is private in outer context", - check_non_private, DECL_NAME (decl)); - remove = true; - } - break; - - case OMP_CLAUSE_DETACH: - flags = GOVD_FIRSTPRIVATE | GOVD_SEEN; - goto do_add; - - case OMP_CLAUSE_IF: - if (OMP_CLAUSE_IF_MODIFIER (c) != ERROR_MARK - && OMP_CLAUSE_IF_MODIFIER (c) != code) - { - const char *p[2]; - for (int i = 0; i < 2; i++) - switch (i ? OMP_CLAUSE_IF_MODIFIER (c) : code) - { - case VOID_CST: p[i] = "cancel"; break; - case OMP_PARALLEL: p[i] = "parallel"; break; - case OMP_SIMD: p[i] = "simd"; break; - case OMP_TASK: p[i] = "task"; break; - case OMP_TASKLOOP: p[i] = "taskloop"; break; - case OMP_TARGET_DATA: p[i] = "target data"; break; - case OMP_TARGET: p[i] = "target"; break; - case OMP_TARGET_UPDATE: p[i] = "target update"; break; - case OMP_TARGET_ENTER_DATA: - p[i] = "target enter data"; break; - case OMP_TARGET_EXIT_DATA: p[i] = "target exit data"; break; - default: gcc_unreachable (); - } - error_at (OMP_CLAUSE_LOCATION (c), - "expected %qs %<if%> clause modifier rather than %qs", - p[0], p[1]); - remove = true; - } - /* Fall through. */ - - case OMP_CLAUSE_FINAL: - OMP_CLAUSE_OPERAND (c, 0) - = gimple_boolify (OMP_CLAUSE_OPERAND (c, 0)); - /* Fall through. */ - - case OMP_CLAUSE_NUM_TEAMS: - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS - && OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) - && !is_gimple_min_invariant (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c))) - { - if (error_operand_p (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c))) - { - remove = true; - break; - } - OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) - = get_initialized_tmp_var (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c), - pre_p, NULL, true); - } - /* Fall through. */ - - case OMP_CLAUSE_SCHEDULE: - case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_THREAD_LIMIT: - case OMP_CLAUSE_DIST_SCHEDULE: - case OMP_CLAUSE_DEVICE: - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE - && OMP_CLAUSE_DEVICE_ANCESTOR (c)) - { - if (code != OMP_TARGET) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<device%> clause with %<ancestor%> is only " - "allowed on %<target%> construct"); - remove = true; - break; - } - - tree clauses = *orig_list_p; - for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) - if (OMP_CLAUSE_CODE (clauses) != OMP_CLAUSE_DEVICE - && OMP_CLAUSE_CODE (clauses) != OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_CODE (clauses) != OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_CODE (clauses) != OMP_CLAUSE_DEFAULTMAP - && OMP_CLAUSE_CODE (clauses) != OMP_CLAUSE_MAP - ) - { - error_at (OMP_CLAUSE_LOCATION (c), - "with %<ancestor%>, only the %<device%>, " - "%<firstprivate%>, %<private%>, %<defaultmap%>, " - "and %<map%> clauses may appear on the " - "construct"); - remove = true; - break; - } - } - /* Fall through. */ - - case OMP_CLAUSE_PRIORITY: - case OMP_CLAUSE_GRAINSIZE: - case OMP_CLAUSE_NUM_TASKS: - case OMP_CLAUSE_FILTER: - case OMP_CLAUSE_HINT: - case OMP_CLAUSE_ASYNC: - case OMP_CLAUSE_WAIT: - case OMP_CLAUSE_NUM_GANGS: - case OMP_CLAUSE_NUM_WORKERS: - case OMP_CLAUSE_VECTOR_LENGTH: - case OMP_CLAUSE_WORKER: - case OMP_CLAUSE_VECTOR: - if (OMP_CLAUSE_OPERAND (c, 0) - && !is_gimple_min_invariant (OMP_CLAUSE_OPERAND (c, 0))) - { - if (error_operand_p (OMP_CLAUSE_OPERAND (c, 0))) - { - remove = true; - break; - } - /* All these clauses care about value, not a particular decl, - so try to force it into a SSA_NAME or fresh temporary. */ - OMP_CLAUSE_OPERAND (c, 0) - = get_initialized_tmp_var (OMP_CLAUSE_OPERAND (c, 0), - pre_p, NULL, true); - } - break; - - case OMP_CLAUSE_GANG: - if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; - if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; - break; - - case OMP_CLAUSE_NOWAIT: - nowait = 1; - break; - - case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_UNTIED: - case OMP_CLAUSE_COLLAPSE: - case OMP_CLAUSE_TILE: - case OMP_CLAUSE_AUTO: - case OMP_CLAUSE_SEQ: - case OMP_CLAUSE_INDEPENDENT: - case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_PROC_BIND: - case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_SIMDLEN: - case OMP_CLAUSE_NOGROUP: - case OMP_CLAUSE_THREADS: - case OMP_CLAUSE_SIMD: - case OMP_CLAUSE_BIND: - case OMP_CLAUSE_IF_PRESENT: - case OMP_CLAUSE_FINALIZE: - break; - - case OMP_CLAUSE_ORDER: - ctx->order_concurrent = true; - break; - - case OMP_CLAUSE_DEFAULTMAP: - enum gimplify_defaultmap_kind gdmkmin, gdmkmax; - switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)) - { - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: - gdmkmin = GDMK_SCALAR; - gdmkmax = GDMK_POINTER; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: - gdmkmin = GDMK_SCALAR; - gdmkmax = GDMK_SCALAR_TARGET; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: - gdmkmin = gdmkmax = GDMK_AGGREGATE; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE: - gdmkmin = gdmkmax = GDMK_ALLOCATABLE; - break; - case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: - gdmkmin = gdmkmax = GDMK_POINTER; - break; - default: - gcc_unreachable (); - } - for (int gdmk = gdmkmin; gdmk <= gdmkmax; gdmk++) - switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (c)) - { - case OMP_CLAUSE_DEFAULTMAP_ALLOC: - ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_ALLOC_ONLY; - break; - case OMP_CLAUSE_DEFAULTMAP_TO: - ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_TO_ONLY; - break; - case OMP_CLAUSE_DEFAULTMAP_FROM: - ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_FROM_ONLY; - break; - case OMP_CLAUSE_DEFAULTMAP_TOFROM: - ctx->defaultmap[gdmk] = GOVD_MAP; - break; - case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE: - ctx->defaultmap[gdmk] = GOVD_FIRSTPRIVATE; - break; - case OMP_CLAUSE_DEFAULTMAP_NONE: - ctx->defaultmap[gdmk] = 0; - break; - case OMP_CLAUSE_DEFAULTMAP_DEFAULT: - switch (gdmk) - { - case GDMK_SCALAR: - ctx->defaultmap[gdmk] = GOVD_FIRSTPRIVATE; - break; - case GDMK_SCALAR_TARGET: - ctx->defaultmap[gdmk] = (lang_GNU_Fortran () - ? GOVD_MAP : GOVD_FIRSTPRIVATE); - break; - case GDMK_AGGREGATE: - case GDMK_ALLOCATABLE: - ctx->defaultmap[gdmk] = GOVD_MAP; - break; - case GDMK_POINTER: - ctx->defaultmap[gdmk] = GOVD_MAP; - if (!lang_GNU_Fortran ()) - ctx->defaultmap[gdmk] |= GOVD_MAP_0LEN_ARRAY; - break; - default: - gcc_unreachable (); - } - break; - default: - gcc_unreachable (); - } - break; - - case OMP_CLAUSE_ALIGNED: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - remove = true; - break; - } - if (gimplify_expr (&OMP_CLAUSE_ALIGNED_ALIGNMENT (c), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - if (!is_global_var (decl) - && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) - omp_add_variable (ctx, decl, GOVD_ALIGNED); - break; - - case OMP_CLAUSE_NONTEMPORAL: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - remove = true; - break; - } - omp_add_variable (ctx, decl, GOVD_NONTEMPORAL); - break; - - case OMP_CLAUSE_ALLOCATE: - decl = OMP_CLAUSE_DECL (c); - if (error_operand_p (decl)) - { - remove = true; - break; - } - if (gimplify_expr (&OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - { - remove = true; - break; - } - else if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE - || (TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) - == INTEGER_CST)) - ; - else if (code == OMP_TASKLOOP - || !DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))) - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - = get_initialized_tmp_var (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), - pre_p, NULL, false); - break; - - case OMP_CLAUSE_DEFAULT: - ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c); - break; - - case OMP_CLAUSE_INCLUSIVE: - case OMP_CLAUSE_EXCLUSIVE: - decl = OMP_CLAUSE_DECL (c); - { - splay_tree_node n = splay_tree_lookup (outer_ctx->variables, - (splay_tree_key) decl); - if (n == NULL || (n->value & GOVD_REDUCTION) == 0) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified in %qs clause but not in %<inscan%> " - "%<reduction%> clause on the containing construct", - decl, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else - { - n->value |= GOVD_REDUCTION_INSCAN; - if (outer_ctx->region_type == ORT_SIMD - && outer_ctx->outer_context - && outer_ctx->outer_context->region_type == ORT_WORKSHARE) - { - n = splay_tree_lookup (outer_ctx->outer_context->variables, - (splay_tree_key) decl); - if (n && (n->value & GOVD_REDUCTION) != 0) - n->value |= GOVD_REDUCTION_INSCAN; - } - } - } - break; - - case OMP_CLAUSE_NOHOST: - default: - gcc_unreachable (); - } - - if (code == OACC_DATA - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) - remove = true; - if (remove) - *list_p = OMP_CLAUSE_CHAIN (c); - else - list_p = &OMP_CLAUSE_CHAIN (c); - } - - ctx->clauses = *orig_list_p; - gimplify_omp_ctxp = ctx; - if (struct_seen_clause) - delete struct_seen_clause; - if (struct_map_to_clause) - delete struct_map_to_clause; - if (struct_deref_set) - delete struct_deref_set; -} - -/* Return true if DECL is a candidate for shared to firstprivate - optimization. We only consider non-addressable scalars, not - too big, and not references. */ - -static bool -omp_shared_to_firstprivate_optimizable_decl_p (tree decl) -{ - if (TREE_ADDRESSABLE (decl)) - return false; - tree type = TREE_TYPE (decl); - if (!is_gimple_reg_type (type) - || TREE_CODE (type) == REFERENCE_TYPE - || TREE_ADDRESSABLE (type)) - return false; - /* Don't optimize too large decls, as each thread/task will have - its own. */ - HOST_WIDE_INT len = int_size_in_bytes (type); - if (len == -1 || len > 4 * POINTER_SIZE / BITS_PER_UNIT) - return false; - if (omp_privatize_by_reference (decl)) - return false; - return true; -} - -/* Helper function of omp_find_stores_op and gimplify_adjust_omp_clauses*. - For omp_shared_to_firstprivate_optimizable_decl_p decl mark it as - GOVD_WRITTEN in outer contexts. */ - -static void -omp_mark_stores (struct gimplify_omp_ctx *ctx, tree decl) -{ - for (; ctx; ctx = ctx->outer_context) - { - splay_tree_node n = splay_tree_lookup (ctx->variables, - (splay_tree_key) decl); - if (n == NULL) - continue; - else if (n->value & GOVD_SHARED) - { - n->value |= GOVD_WRITTEN; - return; - } - else if (n->value & GOVD_DATA_SHARE_CLASS) - return; - } -} - -/* Helper callback for walk_gimple_seq to discover possible stores - to omp_shared_to_firstprivate_optimizable_decl_p decls and set - GOVD_WRITTEN if they are GOVD_SHARED in some outer context - for those. */ - -static tree -omp_find_stores_op (tree *tp, int *walk_subtrees, void *data) -{ - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - - *walk_subtrees = 0; - if (!wi->is_lhs) - return NULL_TREE; - - tree op = *tp; - do - { - if (handled_component_p (op)) - op = TREE_OPERAND (op, 0); - else if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF) - && TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR) - op = TREE_OPERAND (TREE_OPERAND (op, 0), 0); - else - break; - } - while (1); - if (!DECL_P (op) || !omp_shared_to_firstprivate_optimizable_decl_p (op)) - return NULL_TREE; - - omp_mark_stores (gimplify_omp_ctxp, op); - return NULL_TREE; -} - -/* Helper callback for walk_gimple_seq to discover possible stores - to omp_shared_to_firstprivate_optimizable_decl_p decls and set - GOVD_WRITTEN if they are GOVD_SHARED in some outer context - for those. */ - -static tree -omp_find_stores_stmt (gimple_stmt_iterator *gsi_p, - bool *handled_ops_p, - struct walk_stmt_info *wi) -{ - gimple *stmt = gsi_stmt (*gsi_p); - switch (gimple_code (stmt)) - { - /* Don't recurse on OpenMP constructs for which - gimplify_adjust_omp_clauses already handled the bodies, - except handle gimple_omp_for_pre_body. */ - case GIMPLE_OMP_FOR: - *handled_ops_p = true; - if (gimple_omp_for_pre_body (stmt)) - walk_gimple_seq (gimple_omp_for_pre_body (stmt), - omp_find_stores_stmt, omp_find_stores_op, wi); - break; - case GIMPLE_OMP_PARALLEL: - case GIMPLE_OMP_TASK: - case GIMPLE_OMP_SECTIONS: - case GIMPLE_OMP_SINGLE: - case GIMPLE_OMP_SCOPE: - case GIMPLE_OMP_TARGET: - case GIMPLE_OMP_TEAMS: - case GIMPLE_OMP_CRITICAL: - *handled_ops_p = true; - break; - default: - break; - } - return NULL_TREE; -} - -struct gimplify_adjust_omp_clauses_data -{ - tree *list_p; - gimple_seq *pre_p; -}; - -/* For all variables that were not actually used within the context, - remove PRIVATE, SHARED, and FIRSTPRIVATE clauses. */ - -static int -gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) -{ - tree *list_p = ((struct gimplify_adjust_omp_clauses_data *) data)->list_p; - gimple_seq *pre_p - = ((struct gimplify_adjust_omp_clauses_data *) data)->pre_p; - tree decl = (tree) n->key; - unsigned flags = n->value; - enum omp_clause_code code; - tree clause; - bool private_debug; - - if (gimplify_omp_ctxp->region_type == ORT_COMBINED_PARALLEL - && (flags & GOVD_LASTPRIVATE_CONDITIONAL) != 0) - flags = GOVD_SHARED | GOVD_SEEN | GOVD_WRITTEN; - if (flags & (GOVD_EXPLICIT | GOVD_LOCAL)) - return 0; - if ((flags & GOVD_SEEN) == 0) - return 0; - if ((flags & GOVD_MAP_HAS_ATTACHMENTS) != 0) - return 0; - if (flags & GOVD_DEBUG_PRIVATE) - { - gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_SHARED); - private_debug = true; - } - else if (flags & GOVD_MAP) - private_debug = false; - else - private_debug - = lang_hooks.decls.omp_private_debug_clause (decl, - !!(flags & GOVD_SHARED)); - if (private_debug) - code = OMP_CLAUSE_PRIVATE; - else if (flags & GOVD_MAP) - { - code = OMP_CLAUSE_MAP; - if ((gimplify_omp_ctxp->region_type & ORT_ACC) == 0 - && TYPE_ATOMIC (strip_array_types (TREE_TYPE (decl)))) - { - error ("%<_Atomic%> %qD in implicit %<map%> clause", decl); - return 0; - } - if (VAR_P (decl) - && DECL_IN_CONSTANT_POOL (decl) - && !lookup_attribute ("omp declare target", - DECL_ATTRIBUTES (decl))) - { - tree id = get_identifier ("omp declare target"); - DECL_ATTRIBUTES (decl) - = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl)); - varpool_node *node = varpool_node::get (decl); - if (node) - { - node->offloadable = 1; - if (ENABLE_OFFLOADING) - g->have_offload = true; - } - } - } - else if (flags & GOVD_SHARED) - { - if (is_global_var (decl)) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context; - while (ctx != NULL) - { - splay_tree_node on - = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE - | GOVD_PRIVATE | GOVD_REDUCTION - | GOVD_LINEAR | GOVD_MAP)) != 0) - break; - ctx = ctx->outer_context; - } - if (ctx == NULL) - return 0; - } - code = OMP_CLAUSE_SHARED; - /* Don't optimize shared into firstprivate for read-only vars - on tasks with depend clause, we shouldn't try to copy them - until the dependencies are satisfied. */ - if (gimplify_omp_ctxp->has_depend) - flags |= GOVD_WRITTEN; - } - else if (flags & GOVD_PRIVATE) - code = OMP_CLAUSE_PRIVATE; - else if (flags & GOVD_FIRSTPRIVATE) - { - code = OMP_CLAUSE_FIRSTPRIVATE; - if ((gimplify_omp_ctxp->region_type & ORT_TARGET) - && (gimplify_omp_ctxp->region_type & ORT_ACC) == 0 - && TYPE_ATOMIC (strip_array_types (TREE_TYPE (decl)))) - { - error ("%<_Atomic%> %qD in implicit %<firstprivate%> clause on " - "%<target%> construct", decl); - return 0; - } - } - else if (flags & GOVD_LASTPRIVATE) - code = OMP_CLAUSE_LASTPRIVATE; - else if (flags & (GOVD_ALIGNED | GOVD_NONTEMPORAL)) - return 0; - else if (flags & GOVD_CONDTEMP) - { - code = OMP_CLAUSE__CONDTEMP_; - gimple_add_tmp_var (decl); - } - else - gcc_unreachable (); - - if (((flags & GOVD_LASTPRIVATE) - || (code == OMP_CLAUSE_SHARED && (flags & GOVD_WRITTEN))) - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); - - tree chain = *list_p; - clause = build_omp_clause (input_location, code); - OMP_CLAUSE_DECL (clause) = decl; - OMP_CLAUSE_CHAIN (clause) = chain; - if (private_debug) - OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1; - else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF)) - OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1; - else if (code == OMP_CLAUSE_SHARED - && (flags & GOVD_WRITTEN) == 0 - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - OMP_CLAUSE_SHARED_READONLY (clause) = 1; - else if (code == OMP_CLAUSE_FIRSTPRIVATE && (flags & GOVD_EXPLICIT) == 0) - OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (clause) = 1; - else if (code == OMP_CLAUSE_MAP && (flags & GOVD_MAP_0LEN_ARRAY) != 0) - { - tree nc = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = decl; - if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE - && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == POINTER_TYPE) - OMP_CLAUSE_DECL (clause) - = build_simple_mem_ref_loc (input_location, decl); - OMP_CLAUSE_DECL (clause) - = build2 (MEM_REF, char_type_node, OMP_CLAUSE_DECL (clause), - build_int_cst (build_pointer_type (char_type_node), 0)); - OMP_CLAUSE_SIZE (clause) = size_zero_node; - OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_ALLOC); - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (clause) = 1; - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER); - OMP_CLAUSE_CHAIN (nc) = chain; - OMP_CLAUSE_CHAIN (clause) = nc; - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - gimplify_omp_ctxp = ctx->outer_context; - gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0), - pre_p, NULL, is_gimple_val, fb_rvalue); - gimplify_omp_ctxp = ctx; - } - else if (code == OMP_CLAUSE_MAP) - { - int kind; - /* Not all combinations of these GOVD_MAP flags are actually valid. */ - switch (flags & (GOVD_MAP_TO_ONLY - | GOVD_MAP_FORCE - | GOVD_MAP_FORCE_PRESENT - | GOVD_MAP_ALLOC_ONLY - | GOVD_MAP_FROM_ONLY)) - { - case 0: - kind = GOMP_MAP_TOFROM; - break; - case GOVD_MAP_FORCE: - kind = GOMP_MAP_TOFROM | GOMP_MAP_FLAG_FORCE; - break; - case GOVD_MAP_TO_ONLY: - kind = GOMP_MAP_TO; - break; - case GOVD_MAP_FROM_ONLY: - kind = GOMP_MAP_FROM; - break; - case GOVD_MAP_ALLOC_ONLY: - kind = GOMP_MAP_ALLOC; - break; - case GOVD_MAP_TO_ONLY | GOVD_MAP_FORCE: - kind = GOMP_MAP_TO | GOMP_MAP_FLAG_FORCE; - break; - case GOVD_MAP_FORCE_PRESENT: - kind = GOMP_MAP_FORCE_PRESENT; - break; - default: - gcc_unreachable (); - } - OMP_CLAUSE_SET_MAP_KIND (clause, kind); - /* Setting of the implicit flag for the runtime is currently disabled for - OpenACC. */ - if ((gimplify_omp_ctxp->region_type & ORT_ACC) == 0) - OMP_CLAUSE_MAP_RUNTIME_IMPLICIT_P (clause) = 1; - if (DECL_SIZE (decl) - && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) - { - tree decl2 = DECL_VALUE_EXPR (decl); - gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); - decl2 = TREE_OPERAND (decl2, 0); - gcc_assert (DECL_P (decl2)); - tree mem = build_simple_mem_ref (decl2); - OMP_CLAUSE_DECL (clause) = mem; - OMP_CLAUSE_SIZE (clause) = TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (gimplify_omp_ctxp->outer_context) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context; - omp_notice_variable (ctx, decl2, true); - omp_notice_variable (ctx, OMP_CLAUSE_SIZE (clause), true); - } - tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (clause), - OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_SIZE (nc) = size_zero_node; - if (gimplify_omp_ctxp->target_firstprivatize_array_bases) - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER); - else - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); - OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); - OMP_CLAUSE_CHAIN (clause) = nc; - } - else if (gimplify_omp_ctxp->target_firstprivatize_array_bases - && omp_privatize_by_reference (decl)) - { - OMP_CLAUSE_DECL (clause) = build_simple_mem_ref (decl); - OMP_CLAUSE_SIZE (clause) - = unshare_expr (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl)))); - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - gimplify_omp_ctxp = ctx->outer_context; - gimplify_expr (&OMP_CLAUSE_SIZE (clause), - pre_p, NULL, is_gimple_val, fb_rvalue); - gimplify_omp_ctxp = ctx; - tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (clause), - OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_REFERENCE); - OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); - OMP_CLAUSE_CHAIN (clause) = nc; - } - else - OMP_CLAUSE_SIZE (clause) = DECL_SIZE_UNIT (decl); - } - if (code == OMP_CLAUSE_FIRSTPRIVATE && (flags & GOVD_LASTPRIVATE) != 0) - { - tree nc = build_omp_clause (input_location, OMP_CLAUSE_LASTPRIVATE); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (nc) = 1; - OMP_CLAUSE_CHAIN (nc) = chain; - OMP_CLAUSE_CHAIN (clause) = nc; - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - gimplify_omp_ctxp = ctx->outer_context; - lang_hooks.decls.omp_finish_clause (nc, pre_p, - (ctx->region_type & ORT_ACC) != 0); - gimplify_omp_ctxp = ctx; - } - *list_p = clause; - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - gimplify_omp_ctxp = ctx->outer_context; - /* Don't call omp_finish_clause on implicitly added OMP_CLAUSE_PRIVATE - in simd. Those are only added for the local vars inside of simd body - and they don't need to be e.g. default constructible. */ - if (code != OMP_CLAUSE_PRIVATE || ctx->region_type != ORT_SIMD) - lang_hooks.decls.omp_finish_clause (clause, pre_p, - (ctx->region_type & ORT_ACC) != 0); - if (gimplify_omp_ctxp) - for (; clause != chain; clause = OMP_CLAUSE_CHAIN (clause)) - if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP - && DECL_P (OMP_CLAUSE_SIZE (clause))) - omp_notice_variable (gimplify_omp_ctxp, OMP_CLAUSE_SIZE (clause), - true); - gimplify_omp_ctxp = ctx; - return 0; -} - -static void -gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, - enum tree_code code) -{ - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - tree *orig_list_p = list_p; - tree c, decl; - bool has_inscan_reductions = false; - - if (body) - { - struct gimplify_omp_ctx *octx; - for (octx = ctx; octx; octx = octx->outer_context) - if ((octx->region_type & (ORT_PARALLEL | ORT_TASK | ORT_TEAMS)) != 0) - break; - if (octx) - { - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - walk_gimple_seq (body, omp_find_stores_stmt, - omp_find_stores_op, &wi); - } - } - - if (ctx->add_safelen1) - { - /* If there are VLAs in the body of simd loop, prevent - vectorization. */ - gcc_assert (ctx->region_type == ORT_SIMD); - c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_SAFELEN); - OMP_CLAUSE_SAFELEN_EXPR (c) = integer_one_node; - OMP_CLAUSE_CHAIN (c) = *list_p; - *list_p = c; - list_p = &OMP_CLAUSE_CHAIN (c); - } - - if (ctx->region_type == ORT_WORKSHARE - && ctx->outer_context - && ctx->outer_context->region_type == ORT_COMBINED_PARALLEL) - { - for (c = ctx->outer_context->clauses; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - { - decl = OMP_CLAUSE_DECL (c); - splay_tree_node n - = splay_tree_lookup (ctx->outer_context->variables, - (splay_tree_key) decl); - gcc_checking_assert (!splay_tree_lookup (ctx->variables, - (splay_tree_key) decl)); - omp_add_variable (ctx, decl, n->value); - tree c2 = copy_node (c); - OMP_CLAUSE_CHAIN (c2) = *list_p; - *list_p = c2; - if ((n->value & GOVD_FIRSTPRIVATE) == 0) - continue; - c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_CHAIN (c2) = *list_p; - *list_p = c2; - } - } - while ((c = *list_p) != NULL) - { - splay_tree_node n; - bool remove = false; - - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_FIRSTPRIVATE: - if ((ctx->region_type & ORT_TARGET) - && (ctx->region_type & ORT_ACC) == 0 - && TYPE_ATOMIC (strip_array_types - (TREE_TYPE (OMP_CLAUSE_DECL (c))))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qD in %<firstprivate%> clause on " - "%<target%> construct", OMP_CLAUSE_DECL (c)); - remove = true; - break; - } - if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c)) - { - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if ((n->value & GOVD_MAP) != 0) - { - remove = true; - break; - } - OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) = 0; - OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) = 0; - } - /* FALLTHRU */ - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_LINEAR: - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - remove = !(n->value & GOVD_SEEN); - if ((n->value & GOVD_LASTPRIVATE_CONDITIONAL) != 0 - && code == OMP_PARALLEL - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) - remove = true; - if (! remove) - { - bool shared = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED; - if ((n->value & GOVD_DEBUG_PRIVATE) - || lang_hooks.decls.omp_private_debug_clause (decl, shared)) - { - gcc_assert ((n->value & GOVD_DEBUG_PRIVATE) == 0 - || ((n->value & GOVD_DATA_SHARE_CLASS) - == GOVD_SHARED)); - OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_PRIVATE_DEBUG (c) = 1; - } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - && ctx->has_depend - && DECL_P (decl)) - n->value |= GOVD_WRITTEN; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - && (n->value & GOVD_WRITTEN) == 0 - && DECL_P (decl) - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - OMP_CLAUSE_SHARED_READONLY (c) = 1; - else if (DECL_P (decl) - && ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - && (n->value & GOVD_WRITTEN) != 0) - || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); - } - else - n->value &= ~GOVD_EXPLICIT; - break; - - case OMP_CLAUSE_LASTPRIVATE: - /* Make sure OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE is set to - accurately reflect the presence of a FIRSTPRIVATE clause. */ - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c) - = (n->value & GOVD_FIRSTPRIVATE) != 0; - if (code == OMP_DISTRIBUTE - && OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) - { - remove = true; - error_at (OMP_CLAUSE_LOCATION (c), - "same variable used in %<firstprivate%> and " - "%<lastprivate%> clauses on %<distribute%> " - "construct"); - } - if (!remove - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && DECL_P (decl) - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); - if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) && code == OMP_PARALLEL) - remove = true; - break; - - case OMP_CLAUSE_ALIGNED: - decl = OMP_CLAUSE_DECL (c); - if (!is_global_var (decl)) - { - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - remove = n == NULL || !(n->value & GOVD_SEEN); - if (!remove && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) - { - struct gimplify_omp_ctx *octx; - if (n != NULL - && (n->value & (GOVD_DATA_SHARE_CLASS - & ~GOVD_FIRSTPRIVATE))) - remove = true; - else - for (octx = ctx->outer_context; octx; - octx = octx->outer_context) - { - n = splay_tree_lookup (octx->variables, - (splay_tree_key) decl); - if (n == NULL) - continue; - if (n->value & GOVD_LOCAL) - break; - /* We have to avoid assigning a shared variable - to itself when trying to add - __builtin_assume_aligned. */ - if (n->value & GOVD_SHARED) - { - remove = true; - break; - } - } - } - } - else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - { - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) - remove = true; - } - break; - - case OMP_CLAUSE_NONTEMPORAL: - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - remove = n == NULL || !(n->value & GOVD_SEEN); - break; - - case OMP_CLAUSE_MAP: - if (code == OMP_TARGET_EXIT_DATA - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER) - { - remove = true; - break; - } - decl = OMP_CLAUSE_DECL (c); - /* Data clauses associated with reductions must be - compatible with present_or_copy. Warn and adjust the clause - if that is not the case. */ - if (ctx->region_type == ORT_ACC_PARALLEL - || ctx->region_type == ORT_ACC_SERIAL) - { - tree t = DECL_P (decl) ? decl : TREE_OPERAND (decl, 0); - n = NULL; - - if (DECL_P (t)) - n = splay_tree_lookup (ctx->variables, (splay_tree_key) t); - - if (n && (n->value & GOVD_REDUCTION)) - { - enum gomp_map_kind kind = OMP_CLAUSE_MAP_KIND (c); - - OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1; - if ((kind & GOMP_MAP_TOFROM) != GOMP_MAP_TOFROM - && kind != GOMP_MAP_FORCE_PRESENT - && kind != GOMP_MAP_POINTER) - { - warning_at (OMP_CLAUSE_LOCATION (c), 0, - "incompatible data clause with reduction " - "on %qE; promoting to %<present_or_copy%>", - DECL_NAME (t)); - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TOFROM); - } - } - } - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT - && (code == OMP_TARGET_EXIT_DATA || code == OACC_EXIT_DATA)) - { - remove = true; - break; - } - if (!DECL_P (decl)) - { - if ((ctx->region_type & ORT_TARGET) != 0 - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) - { - if (TREE_CODE (decl) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - decl = TREE_OPERAND (decl, 0); - if (TREE_CODE (decl) == COMPONENT_REF) - { - while (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 0); - if (DECL_P (decl)) - { - n = splay_tree_lookup (ctx->variables, - (splay_tree_key) decl); - if (!(n->value & GOVD_SEEN)) - remove = true; - } - } - } - break; - } - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if ((ctx->region_type & ORT_TARGET) != 0 - && !(n->value & GOVD_SEEN) - && GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0 - && (!is_global_var (decl) - || !lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (decl)))) - { - remove = true; - /* For struct element mapping, if struct is never referenced - in target block and none of the mapping has always modifier, - remove all the struct element mappings, which immediately - follow the GOMP_MAP_STRUCT map clause. */ - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT) - { - HOST_WIDE_INT cnt = tree_to_shwi (OMP_CLAUSE_SIZE (c)); - while (cnt--) - OMP_CLAUSE_CHAIN (c) - = OMP_CLAUSE_CHAIN (OMP_CLAUSE_CHAIN (c)); - } - } - else if (DECL_SIZE (decl) - && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER - && (OMP_CLAUSE_MAP_KIND (c) - != GOMP_MAP_FIRSTPRIVATE_REFERENCE)) - { - /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because - for these, TREE_CODE (DECL_SIZE (decl)) will always be - INTEGER_CST. */ - gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); - - tree decl2 = DECL_VALUE_EXPR (decl); - gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); - decl2 = TREE_OPERAND (decl2, 0); - gcc_assert (DECL_P (decl2)); - tree mem = build_simple_mem_ref (decl2); - OMP_CLAUSE_DECL (c) = mem; - OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (ctx->outer_context) - { - omp_notice_variable (ctx->outer_context, decl2, true); - omp_notice_variable (ctx->outer_context, - OMP_CLAUSE_SIZE (c), true); - } - if (((ctx->region_type & ORT_TARGET) != 0 - || !ctx->target_firstprivatize_array_bases) - && ((n->value & GOVD_SEEN) == 0 - || (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) == 0)) - { - tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_SIZE (nc) = size_zero_node; - if (ctx->target_firstprivatize_array_bases) - OMP_CLAUSE_SET_MAP_KIND (nc, - GOMP_MAP_FIRSTPRIVATE_POINTER); - else - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); - OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = nc; - c = nc; - } - } - else - { - if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); - gcc_assert ((n->value & GOVD_SEEN) == 0 - || ((n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) - == 0)); - } - break; - - case OMP_CLAUSE_TO: - case OMP_CLAUSE_FROM: - case OMP_CLAUSE__CACHE_: - decl = OMP_CLAUSE_DECL (c); - if (!DECL_P (decl)) - break; - if (DECL_SIZE (decl) - && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) - { - tree decl2 = DECL_VALUE_EXPR (decl); - gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); - decl2 = TREE_OPERAND (decl2, 0); - gcc_assert (DECL_P (decl2)); - tree mem = build_simple_mem_ref (decl2); - OMP_CLAUSE_DECL (c) = mem; - OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (ctx->outer_context) - { - omp_notice_variable (ctx->outer_context, decl2, true); - omp_notice_variable (ctx->outer_context, - OMP_CLAUSE_SIZE (c), true); - } - } - else if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); - break; - - case OMP_CLAUSE_REDUCTION: - if (OMP_CLAUSE_REDUCTION_INSCAN (c)) - { - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if ((n->value & GOVD_REDUCTION_INSCAN) == 0) - { - remove = true; - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified in %<inscan%> %<reduction%> clause " - "but not in %<scan%> directive clause", decl); - break; - } - has_inscan_reductions = true; - } - /* FALLTHRU */ - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - decl = OMP_CLAUSE_DECL (c); - /* OpenACC reductions need a present_or_copy data clause. - Add one if necessary. Emit error when the reduction is private. */ - if (ctx->region_type == ORT_ACC_PARALLEL - || ctx->region_type == ORT_ACC_SERIAL) - { - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) - { - remove = true; - error_at (OMP_CLAUSE_LOCATION (c), "invalid private " - "reduction on %qE", DECL_NAME (decl)); - } - else if ((n->value & GOVD_MAP) == 0) - { - tree next = OMP_CLAUSE_CHAIN (c); - tree nc = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_TOFROM); - OMP_CLAUSE_DECL (nc) = decl; - OMP_CLAUSE_CHAIN (c) = nc; - lang_hooks.decls.omp_finish_clause (nc, pre_p, - (ctx->region_type - & ORT_ACC) != 0); - while (1) - { - OMP_CLAUSE_MAP_IN_REDUCTION (nc) = 1; - if (OMP_CLAUSE_CHAIN (nc) == NULL) - break; - nc = OMP_CLAUSE_CHAIN (nc); - } - OMP_CLAUSE_CHAIN (nc) = next; - n->value |= GOVD_MAP; - } - } - if (DECL_P (decl) - && omp_shared_to_firstprivate_optimizable_decl_p (decl)) - omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); - break; - - case OMP_CLAUSE_ALLOCATE: - decl = OMP_CLAUSE_DECL (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - if (n != NULL && !(n->value & GOVD_SEEN)) - { - if ((n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LINEAR)) - != 0 - && (n->value & (GOVD_REDUCTION | GOVD_LASTPRIVATE)) == 0) - remove = true; - } - if (!remove - && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - && TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) != INTEGER_CST - && ((ctx->region_type & (ORT_PARALLEL | ORT_TARGET)) != 0 - || (ctx->region_type & ORT_TASKLOOP) == ORT_TASK - || (ctx->region_type & ORT_HOST_TEAMS) == ORT_HOST_TEAMS)) - { - tree allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); - n = splay_tree_lookup (ctx->variables, (splay_tree_key) allocator); - if (n == NULL) - { - enum omp_clause_default_kind default_kind - = ctx->default_kind; - ctx->default_kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), - true); - ctx->default_kind = default_kind; - } - else - omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), - true); - } - break; - - case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_COPYPRIVATE: - case OMP_CLAUSE_IF: - case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_NUM_TEAMS: - case OMP_CLAUSE_THREAD_LIMIT: - case OMP_CLAUSE_DIST_SCHEDULE: - case OMP_CLAUSE_DEVICE: - case OMP_CLAUSE_SCHEDULE: - case OMP_CLAUSE_NOWAIT: - case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_DEFAULT: - case OMP_CLAUSE_UNTIED: - case OMP_CLAUSE_COLLAPSE: - case OMP_CLAUSE_FINAL: - case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_PROC_BIND: - case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_SIMDLEN: - case OMP_CLAUSE_DEPEND: - case OMP_CLAUSE_PRIORITY: - case OMP_CLAUSE_GRAINSIZE: - case OMP_CLAUSE_NUM_TASKS: - case OMP_CLAUSE_NOGROUP: - case OMP_CLAUSE_THREADS: - case OMP_CLAUSE_SIMD: - case OMP_CLAUSE_FILTER: - case OMP_CLAUSE_HINT: - case OMP_CLAUSE_DEFAULTMAP: - case OMP_CLAUSE_ORDER: - case OMP_CLAUSE_BIND: - case OMP_CLAUSE_DETACH: - case OMP_CLAUSE_USE_DEVICE_PTR: - case OMP_CLAUSE_USE_DEVICE_ADDR: - case OMP_CLAUSE_IS_DEVICE_PTR: - case OMP_CLAUSE_ASYNC: - case OMP_CLAUSE_WAIT: - case OMP_CLAUSE_INDEPENDENT: - case OMP_CLAUSE_NUM_GANGS: - case OMP_CLAUSE_NUM_WORKERS: - case OMP_CLAUSE_VECTOR_LENGTH: - case OMP_CLAUSE_GANG: - case OMP_CLAUSE_WORKER: - case OMP_CLAUSE_VECTOR: - case OMP_CLAUSE_AUTO: - case OMP_CLAUSE_SEQ: - case OMP_CLAUSE_TILE: - case OMP_CLAUSE_IF_PRESENT: - case OMP_CLAUSE_FINALIZE: - case OMP_CLAUSE_INCLUSIVE: - case OMP_CLAUSE_EXCLUSIVE: - break; - - case OMP_CLAUSE_NOHOST: - default: - gcc_unreachable (); - } - - if (remove) - *list_p = OMP_CLAUSE_CHAIN (c); - else - list_p = &OMP_CLAUSE_CHAIN (c); - } - - /* Add in any implicit data sharing. */ - struct gimplify_adjust_omp_clauses_data data; - if ((gimplify_omp_ctxp->region_type & ORT_ACC) == 0) - { - /* OpenMP. Implicit clauses are added at the start of the clause list, - but after any non-map clauses. */ - tree *implicit_add_list_p = orig_list_p; - while (*implicit_add_list_p - && OMP_CLAUSE_CODE (*implicit_add_list_p) != OMP_CLAUSE_MAP) - implicit_add_list_p = &OMP_CLAUSE_CHAIN (*implicit_add_list_p); - data.list_p = implicit_add_list_p; - } - else - /* OpenACC. */ - data.list_p = list_p; - data.pre_p = pre_p; - splay_tree_foreach (ctx->variables, gimplify_adjust_omp_clauses_1, &data); - - if (has_inscan_reductions) - for (c = *orig_list_p; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<inscan%> %<reduction%> clause used together with " - "%<linear%> clause for a variable other than loop " - "iterator"); - break; - } - - gimplify_omp_ctxp = ctx->outer_context; - delete_omp_context (ctx); -} - -/* Return 0 if CONSTRUCTS selectors don't match the OpenMP context, - -1 if unknown yet (simd is involved, won't be known until vectorization) - and 1 if they do. If SCORES is non-NULL, it should point to an array - of at least 2*NCONSTRUCTS+2 ints, and will be filled with the positions - of the CONSTRUCTS (position -1 if it will never match) followed by - number of constructs in the OpenMP context construct trait. If the - score depends on whether it will be in a declare simd clone or not, - the function returns 2 and there will be two sets of the scores, the first - one for the case that it is not in a declare simd clone, the other - that it is in a declare simd clone. */ - -int -omp_construct_selector_matches (enum tree_code *constructs, int nconstructs, - int *scores) -{ - int matched = 0, cnt = 0; - bool simd_seen = false; - bool target_seen = false; - int declare_simd_cnt = -1; - auto_vec<enum tree_code, 16> codes; - for (struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; ctx;) - { - if (((ctx->region_type & ORT_PARALLEL) && ctx->code == OMP_PARALLEL) - || ((ctx->region_type & (ORT_TARGET | ORT_IMPLICIT_TARGET | ORT_ACC)) - == ORT_TARGET && ctx->code == OMP_TARGET) - || ((ctx->region_type & ORT_TEAMS) && ctx->code == OMP_TEAMS) - || (ctx->region_type == ORT_WORKSHARE && ctx->code == OMP_FOR) - || (ctx->region_type == ORT_SIMD - && ctx->code == OMP_SIMD - && !omp_find_clause (ctx->clauses, OMP_CLAUSE_BIND))) - { - ++cnt; - if (scores) - codes.safe_push (ctx->code); - else if (matched < nconstructs && ctx->code == constructs[matched]) - { - if (ctx->code == OMP_SIMD) - { - if (matched) - return 0; - simd_seen = true; - } - ++matched; - } - if (ctx->code == OMP_TARGET) - { - if (scores == NULL) - return matched < nconstructs ? 0 : simd_seen ? -1 : 1; - target_seen = true; - break; - } - } - else if (ctx->region_type == ORT_WORKSHARE - && ctx->code == OMP_LOOP - && ctx->outer_context - && ctx->outer_context->region_type == ORT_COMBINED_PARALLEL - && ctx->outer_context->outer_context - && ctx->outer_context->outer_context->code == OMP_LOOP - && ctx->outer_context->outer_context->distribute) - ctx = ctx->outer_context->outer_context; - ctx = ctx->outer_context; - } - if (!target_seen - && lookup_attribute ("omp declare simd", - DECL_ATTRIBUTES (current_function_decl))) - { - /* Declare simd is a maybe case, it is supposed to be added only to the - omp-simd-clone.c added clones and not to the base function. */ - declare_simd_cnt = cnt++; - if (scores) - codes.safe_push (OMP_SIMD); - else if (cnt == 0 - && constructs[0] == OMP_SIMD) - { - gcc_assert (matched == 0); - simd_seen = true; - if (++matched == nconstructs) - return -1; - } - } - if (tree attr = lookup_attribute ("omp declare variant variant", - DECL_ATTRIBUTES (current_function_decl))) - { - enum tree_code variant_constructs[5]; - int variant_nconstructs = 0; - if (!target_seen) - variant_nconstructs - = omp_constructor_traits_to_codes (TREE_VALUE (attr), - variant_constructs); - for (int i = 0; i < variant_nconstructs; i++) - { - ++cnt; - if (scores) - codes.safe_push (variant_constructs[i]); - else if (matched < nconstructs - && variant_constructs[i] == constructs[matched]) - { - if (variant_constructs[i] == OMP_SIMD) - { - if (matched) - return 0; - simd_seen = true; - } - ++matched; - } - } - } - if (!target_seen - && lookup_attribute ("omp declare target block", - DECL_ATTRIBUTES (current_function_decl))) - { - if (scores) - codes.safe_push (OMP_TARGET); - else if (matched < nconstructs && constructs[matched] == OMP_TARGET) - ++matched; - } - if (scores) - { - for (int pass = 0; pass < (declare_simd_cnt == -1 ? 1 : 2); pass++) - { - int j = codes.length () - 1; - for (int i = nconstructs - 1; i >= 0; i--) - { - while (j >= 0 - && (pass != 0 || declare_simd_cnt != j) - && constructs[i] != codes[j]) - --j; - if (pass == 0 && declare_simd_cnt != -1 && j > declare_simd_cnt) - *scores++ = j - 1; - else - *scores++ = j; - } - *scores++ = ((pass == 0 && declare_simd_cnt != -1) - ? codes.length () - 1 : codes.length ()); - } - return declare_simd_cnt == -1 ? 1 : 2; - } - if (matched == nconstructs) - return simd_seen ? -1 : 1; - return 0; -} - -/* Gimplify OACC_CACHE. */ - -static void -gimplify_oacc_cache (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - - gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_ACC, - OACC_CACHE); - gimplify_adjust_omp_clauses (pre_p, NULL, &OACC_CACHE_CLAUSES (expr), - OACC_CACHE); - - /* TODO: Do something sensible with this information. */ - - *expr_p = NULL_TREE; -} - -/* Helper function of gimplify_oacc_declare. The helper's purpose is to, - if required, translate 'kind' in CLAUSE into an 'entry' kind and 'exit' - kind. The entry kind will replace the one in CLAUSE, while the exit - kind will be used in a new omp_clause and returned to the caller. */ - -static tree -gimplify_oacc_declare_1 (tree clause) -{ - HOST_WIDE_INT kind, new_op; - bool ret = false; - tree c = NULL; - - kind = OMP_CLAUSE_MAP_KIND (clause); - - switch (kind) - { - case GOMP_MAP_ALLOC: - new_op = GOMP_MAP_RELEASE; - ret = true; - break; - - case GOMP_MAP_FROM: - OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_FORCE_ALLOC); - new_op = GOMP_MAP_FROM; - ret = true; - break; - - case GOMP_MAP_TOFROM: - OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_TO); - new_op = GOMP_MAP_FROM; - ret = true; - break; - - case GOMP_MAP_DEVICE_RESIDENT: - case GOMP_MAP_FORCE_DEVICEPTR: - case GOMP_MAP_FORCE_PRESENT: - case GOMP_MAP_LINK: - case GOMP_MAP_POINTER: - case GOMP_MAP_TO: - break; - - default: - gcc_unreachable (); - break; - } - - if (ret) - { - c = build_omp_clause (OMP_CLAUSE_LOCATION (clause), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c, new_op); - OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clause); - } - - return c; -} - -/* Gimplify OACC_DECLARE. */ - -static void -gimplify_oacc_declare (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - gomp_target *stmt; - tree clauses, t, decl; - - clauses = OACC_DECLARE_CLAUSES (expr); - - gimplify_scan_omp_clauses (&clauses, pre_p, ORT_TARGET_DATA, OACC_DECLARE); - gimplify_adjust_omp_clauses (pre_p, NULL, &clauses, OACC_DECLARE); - - for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) - { - decl = OMP_CLAUSE_DECL (t); - - if (TREE_CODE (decl) == MEM_REF) - decl = TREE_OPERAND (decl, 0); - - if (VAR_P (decl) && !is_oacc_declared (decl)) - { - tree attr = get_identifier ("oacc declare target"); - DECL_ATTRIBUTES (decl) = tree_cons (attr, NULL_TREE, - DECL_ATTRIBUTES (decl)); - } - - if (VAR_P (decl) - && !is_global_var (decl) - && DECL_CONTEXT (decl) == current_function_decl) - { - tree c = gimplify_oacc_declare_1 (t); - if (c) - { - if (oacc_declare_returns == NULL) - oacc_declare_returns = new hash_map<tree, tree>; - - oacc_declare_returns->put (decl, c); - } - } - - if (gimplify_omp_ctxp) - omp_add_variable (gimplify_omp_ctxp, decl, GOVD_SEEN); - } - - stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_OACC_DECLARE, - clauses); - - gimplify_seq_add_stmt (pre_p, stmt); - - *expr_p = NULL_TREE; -} - -/* Gimplify the contents of an OMP_PARALLEL statement. This involves - gimplification of the body, as well as scanning the body for used - variables. We need to do this scan now, because variable-sized - decls will be decomposed during gimplification. */ - -static void -gimplify_omp_parallel (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - gimple *g; - gimple_seq body = NULL; - - gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, - OMP_PARALLEL_COMBINED (expr) - ? ORT_COMBINED_PARALLEL - : ORT_PARALLEL, OMP_PARALLEL); - - push_gimplify_context (); - - g = gimplify_and_return_first (OMP_PARALLEL_BODY (expr), &body); - if (gimple_code (g) == GIMPLE_BIND) - pop_gimplify_context (g); - else - pop_gimplify_context (NULL); - - gimplify_adjust_omp_clauses (pre_p, body, &OMP_PARALLEL_CLAUSES (expr), - OMP_PARALLEL); - - g = gimple_build_omp_parallel (body, - OMP_PARALLEL_CLAUSES (expr), - NULL_TREE, NULL_TREE); - if (OMP_PARALLEL_COMBINED (expr)) - gimple_omp_set_subcode (g, GF_OMP_PARALLEL_COMBINED); - gimplify_seq_add_stmt (pre_p, g); - *expr_p = NULL_TREE; -} - -/* Gimplify the contents of an OMP_TASK statement. This involves - gimplification of the body, as well as scanning the body for used - variables. We need to do this scan now, because variable-sized - decls will be decomposed during gimplification. */ - -static void -gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - gimple *g; - gimple_seq body = NULL; - - if (OMP_TASK_BODY (expr) == NULL_TREE) - for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<mutexinoutset%> kind in %<depend%> clause on a " - "%<taskwait%> construct"); - break; - } - - gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, - omp_find_clause (OMP_TASK_CLAUSES (expr), - OMP_CLAUSE_UNTIED) - ? ORT_UNTIED_TASK : ORT_TASK, OMP_TASK); - - if (OMP_TASK_BODY (expr)) - { - push_gimplify_context (); - - g = gimplify_and_return_first (OMP_TASK_BODY (expr), &body); - if (gimple_code (g) == GIMPLE_BIND) - pop_gimplify_context (g); - else - pop_gimplify_context (NULL); - } - - gimplify_adjust_omp_clauses (pre_p, body, &OMP_TASK_CLAUSES (expr), - OMP_TASK); - - g = gimple_build_omp_task (body, - OMP_TASK_CLAUSES (expr), - NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE, NULL_TREE); - if (OMP_TASK_BODY (expr) == NULL_TREE) - gimple_omp_task_set_taskwait_p (g, true); - gimplify_seq_add_stmt (pre_p, g); - *expr_p = NULL_TREE; -} - -/* Helper function for gimplify_omp_for. If *TP is not a gimple constant, - force it into a temporary initialized in PRE_P and add firstprivate clause - to ORIG_FOR_STMT. */ - -static void -gimplify_omp_taskloop_expr (tree type, tree *tp, gimple_seq *pre_p, - tree orig_for_stmt) -{ - if (*tp == NULL || is_gimple_constant (*tp)) - return; - - *tp = get_initialized_tmp_var (*tp, pre_p, NULL, false); - /* Reference to pointer conversion is considered useless, - but is significant for firstprivate clause. Force it - here. */ - if (type - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (*tp)) == REFERENCE_TYPE) - { - tree v = create_tmp_var (TYPE_MAIN_VARIANT (type)); - tree m = build2 (INIT_EXPR, TREE_TYPE (v), v, *tp); - gimplify_and_add (m, pre_p); - *tp = v; - } - - tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c) = *tp; - OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (orig_for_stmt); - OMP_FOR_CLAUSES (orig_for_stmt) = c; -} - -/* Gimplify the gross structure of an OMP_FOR statement. */ - -static enum gimplify_status -gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) -{ - tree for_stmt, orig_for_stmt, inner_for_stmt = NULL_TREE, decl, var, t; - enum gimplify_status ret = GS_ALL_DONE; - enum gimplify_status tret; - gomp_for *gfor; - gimple_seq for_body, for_pre_body; - int i; - bitmap has_decl_expr = NULL; - enum omp_region_type ort = ORT_WORKSHARE; - bool openacc = TREE_CODE (*expr_p) == OACC_LOOP; - - orig_for_stmt = for_stmt = *expr_p; - - bool loop_p = (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_BIND) - != NULL_TREE); - if (OMP_FOR_INIT (for_stmt) == NULL_TREE) - { - tree *data[4] = { NULL, NULL, NULL, NULL }; - gcc_assert (TREE_CODE (for_stmt) != OACC_LOOP); - inner_for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), - find_combined_omp_for, data, NULL); - if (inner_for_stmt == NULL_TREE) - { - gcc_assert (seen_error ()); - *expr_p = NULL_TREE; - return GS_ERROR; - } - if (data[2] && OMP_FOR_PRE_BODY (*data[2])) - { - append_to_statement_list_force (OMP_FOR_PRE_BODY (*data[2]), - &OMP_FOR_PRE_BODY (for_stmt)); - OMP_FOR_PRE_BODY (*data[2]) = NULL_TREE; - } - if (OMP_FOR_PRE_BODY (inner_for_stmt)) - { - append_to_statement_list_force (OMP_FOR_PRE_BODY (inner_for_stmt), - &OMP_FOR_PRE_BODY (for_stmt)); - OMP_FOR_PRE_BODY (inner_for_stmt) = NULL_TREE; - } - - if (data[0]) - { - /* We have some statements or variable declarations in between - the composite construct directives. Move them around the - inner_for_stmt. */ - data[0] = expr_p; - for (i = 0; i < 3; i++) - if (data[i]) - { - tree t = *data[i]; - if (i < 2 && data[i + 1] == &OMP_BODY (t)) - data[i + 1] = data[i]; - *data[i] = OMP_BODY (t); - tree body = build3 (BIND_EXPR, void_type_node, NULL_TREE, - NULL_TREE, make_node (BLOCK)); - OMP_BODY (t) = body; - append_to_statement_list_force (inner_for_stmt, - &BIND_EXPR_BODY (body)); - *data[3] = t; - data[3] = tsi_stmt_ptr (tsi_start (BIND_EXPR_BODY (body))); - gcc_assert (*data[3] == inner_for_stmt); - } - return GS_OK; - } - - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++) - if (!loop_p - && OMP_FOR_ORIG_DECLS (inner_for_stmt) - && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), - i)) == TREE_LIST - && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), - i))) - { - tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i); - /* Class iterators aren't allowed on OMP_SIMD, so the only - case we need to solve is distribute parallel for. They are - allowed on the loop construct, but that is already handled - in gimplify_omp_loop. */ - gcc_assert (TREE_CODE (inner_for_stmt) == OMP_FOR - && TREE_CODE (for_stmt) == OMP_DISTRIBUTE - && data[1]); - tree orig_decl = TREE_PURPOSE (orig); - tree last = TREE_VALUE (orig); - tree *pc; - for (pc = &OMP_FOR_CLAUSES (inner_for_stmt); - *pc; pc = &OMP_CLAUSE_CHAIN (*pc)) - if ((OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (*pc) == orig_decl) - break; - if (*pc == NULL_TREE) - { - tree *spc; - for (spc = &OMP_PARALLEL_CLAUSES (*data[1]); - *spc; spc = &OMP_CLAUSE_CHAIN (*spc)) - if (OMP_CLAUSE_CODE (*spc) == OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_DECL (*spc) == orig_decl) - break; - if (*spc) - { - tree c = *spc; - *spc = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = NULL_TREE; - *pc = c; - } - } - if (*pc == NULL_TREE) - ; - else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE) - { - /* private clause will appear only on inner_for_stmt. - Change it into firstprivate, and add private clause - on for_stmt. */ - tree c = copy_node (*pc); - OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); - OMP_FOR_CLAUSES (for_stmt) = c; - OMP_CLAUSE_CODE (*pc) = OMP_CLAUSE_FIRSTPRIVATE; - lang_hooks.decls.omp_finish_clause (*pc, pre_p, openacc); - } - else - { - /* lastprivate clause will appear on both inner_for_stmt - and for_stmt. Add firstprivate clause to - inner_for_stmt. */ - tree c = build_omp_clause (OMP_CLAUSE_LOCATION (*pc), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (*pc); - OMP_CLAUSE_CHAIN (c) = *pc; - *pc = c; - lang_hooks.decls.omp_finish_clause (*pc, pre_p, openacc); - } - tree c = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c) = last; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); - OMP_PARALLEL_CLAUSES (*data[1]) = c; - c = build_omp_clause (UNKNOWN_LOCATION, - *pc ? OMP_CLAUSE_SHARED - : OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c) = orig_decl; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); - OMP_PARALLEL_CLAUSES (*data[1]) = c; - } - /* Similarly, take care of C++ range for temporaries, those should - be firstprivate on OMP_PARALLEL if any. */ - if (data[1]) - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++) - if (OMP_FOR_ORIG_DECLS (inner_for_stmt) - && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), - i)) == TREE_LIST - && TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), - i))) - { - tree orig - = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i); - tree v = TREE_CHAIN (orig); - tree c = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE_FIRSTPRIVATE); - /* First add firstprivate clause for the __for_end artificial - decl. */ - OMP_CLAUSE_DECL (c) = TREE_VEC_ELT (v, 1); - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) - == REFERENCE_TYPE) - OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c) = 1; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); - OMP_PARALLEL_CLAUSES (*data[1]) = c; - if (TREE_VEC_ELT (v, 0)) - { - /* And now the same for __for_range artificial decl if it - exists. */ - c = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (c) = TREE_VEC_ELT (v, 0); - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) - == REFERENCE_TYPE) - OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c) = 1; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); - OMP_PARALLEL_CLAUSES (*data[1]) = c; - } - } - } - - switch (TREE_CODE (for_stmt)) - { - case OMP_FOR: - if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt)) - { - if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), - OMP_CLAUSE_SCHEDULE)) - error_at (EXPR_LOCATION (for_stmt), - "%qs clause may not appear on non-rectangular %qs", - "schedule", "for"); - if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED)) - error_at (EXPR_LOCATION (for_stmt), - "%qs clause may not appear on non-rectangular %qs", - "ordered", "for"); - } - break; - case OMP_DISTRIBUTE: - if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt) - && omp_find_clause (OMP_FOR_CLAUSES (for_stmt), - OMP_CLAUSE_DIST_SCHEDULE)) - error_at (EXPR_LOCATION (for_stmt), - "%qs clause may not appear on non-rectangular %qs", - "dist_schedule", "distribute"); - break; - case OACC_LOOP: - ort = ORT_ACC; - break; - case OMP_TASKLOOP: - if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_UNTIED)) - ort = ORT_UNTIED_TASKLOOP; - else - ort = ORT_TASKLOOP; - break; - case OMP_SIMD: - ort = ORT_SIMD; - break; - default: - gcc_unreachable (); - } - - /* Set OMP_CLAUSE_LINEAR_NO_COPYIN flag on explicit linear - clause for the IV. */ - if (ort == ORT_SIMD && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), 0); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - decl = TREE_OPERAND (t, 0); - for (tree c = OMP_FOR_CLAUSES (for_stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && OMP_CLAUSE_DECL (c) == decl) - { - OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; - break; - } - } - - if (TREE_CODE (for_stmt) != OMP_TASKLOOP) - gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort, - loop_p && TREE_CODE (for_stmt) != OMP_SIMD - ? OMP_LOOP : TREE_CODE (for_stmt)); - - if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE) - gimplify_omp_ctxp->distribute = true; - - /* Handle OMP_FOR_INIT. */ - for_pre_body = NULL; - if ((ort == ORT_SIMD - || (inner_for_stmt && TREE_CODE (inner_for_stmt) == OMP_SIMD)) - && OMP_FOR_PRE_BODY (for_stmt)) - { - has_decl_expr = BITMAP_ALLOC (NULL); - if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR - && TREE_CODE (DECL_EXPR_DECL (OMP_FOR_PRE_BODY (for_stmt))) - == VAR_DECL) - { - t = OMP_FOR_PRE_BODY (for_stmt); - bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); - } - else if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == STATEMENT_LIST) - { - tree_stmt_iterator si; - for (si = tsi_start (OMP_FOR_PRE_BODY (for_stmt)); !tsi_end_p (si); - tsi_next (&si)) - { - t = tsi_stmt (si); - if (TREE_CODE (t) == DECL_EXPR - && TREE_CODE (DECL_EXPR_DECL (t)) == VAR_DECL) - bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); - } - } - } - if (OMP_FOR_PRE_BODY (for_stmt)) - { - if (TREE_CODE (for_stmt) != OMP_TASKLOOP || gimplify_omp_ctxp) - gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); - else - { - struct gimplify_omp_ctx ctx; - memset (&ctx, 0, sizeof (ctx)); - ctx.region_type = ORT_NONE; - gimplify_omp_ctxp = &ctx; - gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); - gimplify_omp_ctxp = NULL; - } - } - OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE; - - if (OMP_FOR_INIT (for_stmt) == NULL_TREE) - for_stmt = inner_for_stmt; - - /* For taskloop, need to gimplify the start, end and step before the - taskloop, outside of the taskloop omp context. */ - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) - { - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - gimple_seq *for_pre_p = (gimple_seq_empty_p (for_pre_body) - ? pre_p : &for_pre_body); - tree type = TREE_TYPE (TREE_OPERAND (t, 0)); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC) - { - tree v = TREE_OPERAND (t, 1); - gimplify_omp_taskloop_expr (type, &TREE_VEC_ELT (v, 1), - for_pre_p, orig_for_stmt); - gimplify_omp_taskloop_expr (type, &TREE_VEC_ELT (v, 2), - for_pre_p, orig_for_stmt); - } - else - gimplify_omp_taskloop_expr (type, &TREE_OPERAND (t, 1), for_pre_p, - orig_for_stmt); - - /* Handle OMP_FOR_COND. */ - t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC) - { - tree v = TREE_OPERAND (t, 1); - gimplify_omp_taskloop_expr (type, &TREE_VEC_ELT (v, 1), - for_pre_p, orig_for_stmt); - gimplify_omp_taskloop_expr (type, &TREE_VEC_ELT (v, 2), - for_pre_p, orig_for_stmt); - } - else - gimplify_omp_taskloop_expr (type, &TREE_OPERAND (t, 1), for_pre_p, - orig_for_stmt); - - /* Handle OMP_FOR_INCR. */ - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - if (TREE_CODE (t) == MODIFY_EXPR) - { - decl = TREE_OPERAND (t, 0); - t = TREE_OPERAND (t, 1); - tree *tp = &TREE_OPERAND (t, 1); - if (TREE_CODE (t) == PLUS_EXPR && *tp == decl) - tp = &TREE_OPERAND (t, 0); - - gimplify_omp_taskloop_expr (NULL_TREE, tp, for_pre_p, - orig_for_stmt); - } - } - - gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt), pre_p, ort, - OMP_TASKLOOP); - } - - if (orig_for_stmt != for_stmt) - gimplify_omp_ctxp->combined_loop = true; - - for_body = NULL; - gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) - == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt))); - gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) - == TREE_VEC_LENGTH (OMP_FOR_INCR (for_stmt))); - - tree c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED); - bool is_doacross = false; - if (c && OMP_CLAUSE_ORDERED_EXPR (c)) - { - is_doacross = true; - gimplify_omp_ctxp->loop_iter_var.create (TREE_VEC_LENGTH - (OMP_FOR_INIT (for_stmt)) - * 2); - } - int collapse = 1, tile = 0; - c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_COLLAPSE); - if (c) - collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (c)); - c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_TILE); - if (c) - tile = list_length (OMP_CLAUSE_TILE_LIST (c)); - c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ALLOCATE); - hash_set<tree> *allocate_uids = NULL; - if (c) - { - allocate_uids = new hash_set<tree>; - for (; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE) - allocate_uids->add (OMP_CLAUSE_DECL (c)); - } - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - decl = TREE_OPERAND (t, 0); - gcc_assert (DECL_P (decl)); - gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)) - || POINTER_TYPE_P (TREE_TYPE (decl))); - if (is_doacross) - { - if (TREE_CODE (for_stmt) == OMP_FOR && OMP_FOR_ORIG_DECLS (for_stmt)) - { - tree orig_decl = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); - if (TREE_CODE (orig_decl) == TREE_LIST) - { - orig_decl = TREE_PURPOSE (orig_decl); - if (!orig_decl) - orig_decl = decl; - } - gimplify_omp_ctxp->loop_iter_var.quick_push (orig_decl); - } - else - gimplify_omp_ctxp->loop_iter_var.quick_push (decl); - gimplify_omp_ctxp->loop_iter_var.quick_push (decl); - } - - if (for_stmt == orig_for_stmt) - { - tree orig_decl = decl; - if (OMP_FOR_ORIG_DECLS (for_stmt)) - { - tree orig_decl = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); - if (TREE_CODE (orig_decl) == TREE_LIST) - { - orig_decl = TREE_PURPOSE (orig_decl); - if (!orig_decl) - orig_decl = decl; - } - } - if (is_global_var (orig_decl) && DECL_THREAD_LOCAL_P (orig_decl)) - error_at (EXPR_LOCATION (for_stmt), - "threadprivate iteration variable %qD", orig_decl); - } - - /* Make sure the iteration variable is private. */ - tree c = NULL_TREE; - tree c2 = NULL_TREE; - if (orig_for_stmt != for_stmt) - { - /* Preserve this information until we gimplify the inner simd. */ - if (has_decl_expr - && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) - TREE_PRIVATE (t) = 1; - } - else if (ort == ORT_SIMD) - { - splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, - (splay_tree_key) decl); - omp_is_private (gimplify_omp_ctxp, decl, - 1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) - != 1)); - if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) - { - omp_notice_variable (gimplify_omp_ctxp, decl, true); - if (n->value & GOVD_LASTPRIVATE_CONDITIONAL) - for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), - OMP_CLAUSE_LASTPRIVATE); - c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3), - OMP_CLAUSE_LASTPRIVATE)) - if (OMP_CLAUSE_DECL (c3) == decl) - { - warning_at (OMP_CLAUSE_LOCATION (c3), 0, - "conditional %<lastprivate%> on loop " - "iterator %qD ignored", decl); - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0; - n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL; - } - } - else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1 && !loop_p) - { - c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); - OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; - unsigned int flags = GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN; - if ((has_decl_expr - && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) - || TREE_PRIVATE (t)) - { - OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; - flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; - } - struct gimplify_omp_ctx *outer - = gimplify_omp_ctxp->outer_context; - if (outer && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - { - if (outer->region_type == ORT_WORKSHARE - && outer->combined_loop) - { - n = splay_tree_lookup (outer->variables, - (splay_tree_key)decl); - if (n != NULL && (n->value & GOVD_LOCAL) != 0) - { - OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; - flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; - } - else - { - struct gimplify_omp_ctx *octx = outer->outer_context; - if (octx - && octx->region_type == ORT_COMBINED_PARALLEL - && octx->outer_context - && (octx->outer_context->region_type - == ORT_WORKSHARE) - && octx->outer_context->combined_loop) - { - octx = octx->outer_context; - n = splay_tree_lookup (octx->variables, - (splay_tree_key)decl); - if (n != NULL && (n->value & GOVD_LOCAL) != 0) - { - OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; - flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; - } - } - } - } - } - - OMP_CLAUSE_DECL (c) = decl; - OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); - OMP_FOR_CLAUSES (for_stmt) = c; - omp_add_variable (gimplify_omp_ctxp, decl, flags); - if (outer && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) - omp_lastprivate_for_combined_outer_constructs (outer, decl, - true); - } - else - { - bool lastprivate - = (!has_decl_expr - || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); - if (TREE_PRIVATE (t)) - lastprivate = false; - if (loop_p && OMP_FOR_ORIG_DECLS (for_stmt)) - { - tree elt = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); - if (TREE_CODE (elt) == TREE_LIST && TREE_PURPOSE (elt)) - lastprivate = false; - } - - struct gimplify_omp_ctx *outer - = gimplify_omp_ctxp->outer_context; - if (outer && lastprivate) - omp_lastprivate_for_combined_outer_constructs (outer, decl, - true); - - c = build_omp_clause (input_location, - lastprivate ? OMP_CLAUSE_LASTPRIVATE - : OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_DECL (c) = decl; - OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); - OMP_FOR_CLAUSES (for_stmt) = c; - omp_add_variable (gimplify_omp_ctxp, decl, - (lastprivate ? GOVD_LASTPRIVATE : GOVD_PRIVATE) - | GOVD_EXPLICIT | GOVD_SEEN); - c = NULL_TREE; - } - } - else if (omp_is_private (gimplify_omp_ctxp, decl, 0)) - { - omp_notice_variable (gimplify_omp_ctxp, decl, true); - splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, - (splay_tree_key) decl); - if (n && (n->value & GOVD_LASTPRIVATE_CONDITIONAL)) - for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), - OMP_CLAUSE_LASTPRIVATE); - c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3), - OMP_CLAUSE_LASTPRIVATE)) - if (OMP_CLAUSE_DECL (c3) == decl) - { - warning_at (OMP_CLAUSE_LOCATION (c3), 0, - "conditional %<lastprivate%> on loop " - "iterator %qD ignored", decl); - OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0; - n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL; - } - } - else - omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); - - /* If DECL is not a gimple register, create a temporary variable to act - as an iteration counter. This is valid, since DECL cannot be - modified in the body of the loop. Similarly for any iteration vars - in simd with collapse > 1 where the iterator vars must be - lastprivate. And similarly for vars mentioned in allocate clauses. */ - if (orig_for_stmt != for_stmt) - var = decl; - else if (!is_gimple_reg (decl) - || (ort == ORT_SIMD - && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) - || (allocate_uids && allocate_uids->contains (decl))) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - /* Make sure omp_add_variable is not called on it prematurely. - We call it ourselves a few lines later. */ - gimplify_omp_ctxp = NULL; - var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); - gimplify_omp_ctxp = ctx; - TREE_OPERAND (t, 0) = var; - - gimplify_seq_add_stmt (&for_body, gimple_build_assign (decl, var)); - - if (ort == ORT_SIMD - && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) - { - c2 = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); - OMP_CLAUSE_LINEAR_NO_COPYIN (c2) = 1; - OMP_CLAUSE_LINEAR_NO_COPYOUT (c2) = 1; - OMP_CLAUSE_DECL (c2) = var; - OMP_CLAUSE_CHAIN (c2) = OMP_FOR_CLAUSES (for_stmt); - OMP_FOR_CLAUSES (for_stmt) = c2; - omp_add_variable (gimplify_omp_ctxp, var, - GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); - if (c == NULL_TREE) - { - c = c2; - c2 = NULL_TREE; - } - } - else - omp_add_variable (gimplify_omp_ctxp, var, - GOVD_PRIVATE | GOVD_SEEN); - } - else - var = decl; - - gimplify_omp_ctxp->in_for_exprs = true; - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC) - { - tree lb = TREE_OPERAND (t, 1); - tret = gimplify_expr (&TREE_VEC_ELT (lb, 1), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - ret = MIN (ret, tret); - tret = gimplify_expr (&TREE_VEC_ELT (lb, 2), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - } - else - tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - gimplify_omp_ctxp->in_for_exprs = false; - ret = MIN (ret, tret); - if (ret == GS_ERROR) - return ret; - - /* Handle OMP_FOR_COND. */ - t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i); - gcc_assert (COMPARISON_CLASS_P (t)); - gcc_assert (TREE_OPERAND (t, 0) == decl); - - gimplify_omp_ctxp->in_for_exprs = true; - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC) - { - tree ub = TREE_OPERAND (t, 1); - tret = gimplify_expr (&TREE_VEC_ELT (ub, 1), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - ret = MIN (ret, tret); - tret = gimplify_expr (&TREE_VEC_ELT (ub, 2), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - } - else - tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - gimplify_omp_ctxp->in_for_exprs = false; - ret = MIN (ret, tret); - - /* Handle OMP_FOR_INCR. */ - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - switch (TREE_CODE (t)) - { - case PREINCREMENT_EXPR: - case POSTINCREMENT_EXPR: - { - tree decl = TREE_OPERAND (t, 0); - /* c_omp_for_incr_canonicalize_ptr() should have been - called to massage things appropriately. */ - gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); - - if (orig_for_stmt != for_stmt) - break; - t = build_int_cst (TREE_TYPE (decl), 1); - if (c) - OMP_CLAUSE_LINEAR_STEP (c) = t; - t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); - t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); - TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; - break; - } - - case PREDECREMENT_EXPR: - case POSTDECREMENT_EXPR: - /* c_omp_for_incr_canonicalize_ptr() should have been - called to massage things appropriately. */ - gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); - if (orig_for_stmt != for_stmt) - break; - t = build_int_cst (TREE_TYPE (decl), -1); - if (c) - OMP_CLAUSE_LINEAR_STEP (c) = t; - t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); - t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); - TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; - break; - - case MODIFY_EXPR: - gcc_assert (TREE_OPERAND (t, 0) == decl); - TREE_OPERAND (t, 0) = var; - - t = TREE_OPERAND (t, 1); - switch (TREE_CODE (t)) - { - case PLUS_EXPR: - if (TREE_OPERAND (t, 1) == decl) - { - TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0); - TREE_OPERAND (t, 0) = var; - break; - } - - /* Fallthru. */ - case MINUS_EXPR: - case POINTER_PLUS_EXPR: - gcc_assert (TREE_OPERAND (t, 0) == decl); - TREE_OPERAND (t, 0) = var; - break; - default: - gcc_unreachable (); - } - - gimplify_omp_ctxp->in_for_exprs = true; - tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - ret = MIN (ret, tret); - if (c) - { - tree step = TREE_OPERAND (t, 1); - tree stept = TREE_TYPE (decl); - if (POINTER_TYPE_P (stept)) - stept = sizetype; - step = fold_convert (stept, step); - if (TREE_CODE (t) == MINUS_EXPR) - step = fold_build1 (NEGATE_EXPR, stept, step); - OMP_CLAUSE_LINEAR_STEP (c) = step; - if (step != TREE_OPERAND (t, 1)) - { - tret = gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), - &for_pre_body, NULL, - is_gimple_val, fb_rvalue, false); - ret = MIN (ret, tret); - } - } - gimplify_omp_ctxp->in_for_exprs = false; - break; - - default: - gcc_unreachable (); - } - - if (c2) - { - gcc_assert (c); - OMP_CLAUSE_LINEAR_STEP (c2) = OMP_CLAUSE_LINEAR_STEP (c); - } - - if ((var != decl || collapse > 1 || tile) && orig_for_stmt == for_stmt) - { - for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) - if (((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) == NULL) - || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c) - && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) == NULL)) - && OMP_CLAUSE_DECL (c) == decl) - { - if (is_doacross && (collapse == 1 || i >= collapse)) - t = var; - else - { - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - gcc_assert (TREE_OPERAND (t, 0) == var); - t = TREE_OPERAND (t, 1); - gcc_assert (TREE_CODE (t) == PLUS_EXPR - || TREE_CODE (t) == MINUS_EXPR - || TREE_CODE (t) == POINTER_PLUS_EXPR); - gcc_assert (TREE_OPERAND (t, 0) == var); - t = build2 (TREE_CODE (t), TREE_TYPE (decl), - is_doacross ? var : decl, - TREE_OPERAND (t, 1)); - } - gimple_seq *seq; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - seq = &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c); - else - seq = &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c); - push_gimplify_context (); - gimplify_assign (decl, t, seq); - gimple *bind = NULL; - if (gimplify_ctxp->temps) - { - bind = gimple_build_bind (NULL_TREE, *seq, NULL_TREE); - *seq = NULL; - gimplify_seq_add_stmt (seq, bind); - } - pop_gimplify_context (bind); - } - } - if (OMP_FOR_NON_RECTANGULAR (for_stmt) && var != decl) - for (int j = i + 1; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC - && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl) - TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var; - t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j); - gcc_assert (COMPARISON_CLASS_P (t)); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC - && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl) - TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var; - } - } - - BITMAP_FREE (has_decl_expr); - delete allocate_uids; - - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP - || (loop_p && orig_for_stmt == for_stmt)) - { - push_gimplify_context (); - if (TREE_CODE (OMP_FOR_BODY (orig_for_stmt)) != BIND_EXPR) - { - OMP_FOR_BODY (orig_for_stmt) - = build3 (BIND_EXPR, void_type_node, NULL, - OMP_FOR_BODY (orig_for_stmt), NULL); - TREE_SIDE_EFFECTS (OMP_FOR_BODY (orig_for_stmt)) = 1; - } - } - - gimple *g = gimplify_and_return_first (OMP_FOR_BODY (orig_for_stmt), - &for_body); - - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP - || (loop_p && orig_for_stmt == for_stmt)) - { - if (gimple_code (g) == GIMPLE_BIND) - pop_gimplify_context (g); - else - pop_gimplify_context (NULL); - } - - if (orig_for_stmt != for_stmt) - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - decl = TREE_OPERAND (t, 0); - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) - gimplify_omp_ctxp = ctx->outer_context; - var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); - gimplify_omp_ctxp = ctx; - omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN); - TREE_OPERAND (t, 0) = var; - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1)); - TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var; - if (OMP_FOR_NON_RECTANGULAR (for_stmt)) - for (int j = i + 1; - j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC - && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl) - { - TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1)); - TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var; - } - t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j); - gcc_assert (COMPARISON_CLASS_P (t)); - if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC - && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl) - { - TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1)); - TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var; - } - } - } - - gimplify_adjust_omp_clauses (pre_p, for_body, - &OMP_FOR_CLAUSES (orig_for_stmt), - TREE_CODE (orig_for_stmt)); - - int kind; - switch (TREE_CODE (orig_for_stmt)) - { - case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; - case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; - case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; - case OMP_TASKLOOP: kind = GF_OMP_FOR_KIND_TASKLOOP; break; - case OACC_LOOP: kind = GF_OMP_FOR_KIND_OACC_LOOP; break; - default: - gcc_unreachable (); - } - if (loop_p && kind == GF_OMP_FOR_KIND_SIMD) - { - gimplify_seq_add_seq (pre_p, for_pre_body); - for_pre_body = NULL; - } - gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt), - TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), - for_pre_body); - if (orig_for_stmt != for_stmt) - gimple_omp_for_set_combined_p (gfor, true); - if (gimplify_omp_ctxp - && (gimplify_omp_ctxp->combined_loop - || (gimplify_omp_ctxp->region_type == ORT_COMBINED_PARALLEL - && gimplify_omp_ctxp->outer_context - && gimplify_omp_ctxp->outer_context->combined_loop))) - { - gimple_omp_for_set_combined_into_p (gfor, true); - if (gimplify_omp_ctxp->combined_loop) - gcc_assert (TREE_CODE (orig_for_stmt) == OMP_SIMD); - else - gcc_assert (TREE_CODE (orig_for_stmt) == OMP_FOR); - } - - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - { - t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - gimple_omp_for_set_index (gfor, i, TREE_OPERAND (t, 0)); - gimple_omp_for_set_initial (gfor, i, TREE_OPERAND (t, 1)); - t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i); - gimple_omp_for_set_cond (gfor, i, TREE_CODE (t)); - gimple_omp_for_set_final (gfor, i, TREE_OPERAND (t, 1)); - t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); - gimple_omp_for_set_incr (gfor, i, TREE_OPERAND (t, 1)); - } - - /* OMP_TASKLOOP is gimplified as two GIMPLE_OMP_FOR taskloop - constructs with GIMPLE_OMP_TASK sandwiched in between them. - The outer taskloop stands for computing the number of iterations, - counts for collapsed loops and holding taskloop specific clauses. - The task construct stands for the effect of data sharing on the - explicit task it creates and the inner taskloop stands for expansion - of the static loop inside of the explicit task construct. */ - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) - { - tree *gfor_clauses_ptr = gimple_omp_for_clauses_ptr (gfor); - tree task_clauses = NULL_TREE; - tree c = *gfor_clauses_ptr; - tree *gtask_clauses_ptr = &task_clauses; - tree outer_for_clauses = NULL_TREE; - tree *gforo_clauses_ptr = &outer_for_clauses; - bitmap lastprivate_uids = NULL; - if (omp_find_clause (c, OMP_CLAUSE_ALLOCATE)) - { - c = omp_find_clause (c, OMP_CLAUSE_LASTPRIVATE); - if (c) - { - lastprivate_uids = BITMAP_ALLOC (NULL); - for (; c; c = omp_find_clause (OMP_CLAUSE_CHAIN (c), - OMP_CLAUSE_LASTPRIVATE)) - bitmap_set_bit (lastprivate_uids, - DECL_UID (OMP_CLAUSE_DECL (c))); - } - c = *gfor_clauses_ptr; - } - for (; c; c = OMP_CLAUSE_CHAIN (c)) - switch (OMP_CLAUSE_CODE (c)) - { - /* These clauses are allowed on task, move them there. */ - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_DEFAULT: - case OMP_CLAUSE_IF: - case OMP_CLAUSE_UNTIED: - case OMP_CLAUSE_FINAL: - case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_PRIORITY: - case OMP_CLAUSE_REDUCTION: - case OMP_CLAUSE_IN_REDUCTION: - *gtask_clauses_ptr = c; - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - break; - case OMP_CLAUSE_PRIVATE: - if (OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c)) - { - /* We want private on outer for and firstprivate - on task. */ - *gtask_clauses_ptr - = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); - lang_hooks.decls.omp_finish_clause (*gtask_clauses_ptr, NULL, - openacc); - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); - *gforo_clauses_ptr = c; - gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - } - else - { - *gtask_clauses_ptr = c; - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - } - break; - /* These clauses go into outer taskloop clauses. */ - case OMP_CLAUSE_GRAINSIZE: - case OMP_CLAUSE_NUM_TASKS: - case OMP_CLAUSE_NOGROUP: - *gforo_clauses_ptr = c; - gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - break; - /* Collapse clause we duplicate on both taskloops. */ - case OMP_CLAUSE_COLLAPSE: - *gfor_clauses_ptr = c; - gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - *gforo_clauses_ptr = copy_node (c); - gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (*gforo_clauses_ptr); - break; - /* For lastprivate, keep the clause on inner taskloop, and add - a shared clause on task. If the same decl is also firstprivate, - add also firstprivate clause on the inner taskloop. */ - case OMP_CLAUSE_LASTPRIVATE: - if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c)) - { - /* For taskloop C++ lastprivate IVs, we want: - 1) private on outer taskloop - 2) firstprivate and shared on task - 3) lastprivate on inner taskloop */ - *gtask_clauses_ptr - = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); - lang_hooks.decls.omp_finish_clause (*gtask_clauses_ptr, NULL, - openacc); - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); - OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c) = 1; - *gforo_clauses_ptr = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_DECL (*gforo_clauses_ptr) = OMP_CLAUSE_DECL (c); - OMP_CLAUSE_PRIVATE_TASKLOOP_IV (*gforo_clauses_ptr) = 1; - TREE_TYPE (*gforo_clauses_ptr) = TREE_TYPE (c); - gforo_clauses_ptr = &OMP_CLAUSE_CHAIN (*gforo_clauses_ptr); - } - *gfor_clauses_ptr = c; - gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - *gtask_clauses_ptr - = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_SHARED); - OMP_CLAUSE_DECL (*gtask_clauses_ptr) = OMP_CLAUSE_DECL (c); - if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) - OMP_CLAUSE_SHARED_FIRSTPRIVATE (*gtask_clauses_ptr) = 1; - gtask_clauses_ptr - = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); - break; - /* Allocate clause we duplicate on task and inner taskloop - if the decl is lastprivate, otherwise just put on task. */ - case OMP_CLAUSE_ALLOCATE: - if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - && DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))) - { - /* Additionally, put firstprivate clause on task - for the allocator if it is not constant. */ - *gtask_clauses_ptr - = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (*gtask_clauses_ptr) - = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); - } - if (lastprivate_uids - && bitmap_bit_p (lastprivate_uids, - DECL_UID (OMP_CLAUSE_DECL (c)))) - { - *gfor_clauses_ptr = c; - gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - *gtask_clauses_ptr = copy_node (c); - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr); - } - else - { - *gtask_clauses_ptr = c; - gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (c); - } - break; - default: - gcc_unreachable (); - } - *gfor_clauses_ptr = NULL_TREE; - *gtask_clauses_ptr = NULL_TREE; - *gforo_clauses_ptr = NULL_TREE; - BITMAP_FREE (lastprivate_uids); - g = gimple_build_bind (NULL_TREE, gfor, NULL_TREE); - g = gimple_build_omp_task (g, task_clauses, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE, NULL_TREE); - gimple_omp_task_set_taskloop_p (g, true); - g = gimple_build_bind (NULL_TREE, g, NULL_TREE); - gomp_for *gforo - = gimple_build_omp_for (g, GF_OMP_FOR_KIND_TASKLOOP, outer_for_clauses, - gimple_omp_for_collapse (gfor), - gimple_omp_for_pre_body (gfor)); - gimple_omp_for_set_pre_body (gfor, NULL); - gimple_omp_for_set_combined_p (gforo, true); - gimple_omp_for_set_combined_into_p (gfor, true); - for (i = 0; i < (int) gimple_omp_for_collapse (gfor); i++) - { - tree type = TREE_TYPE (gimple_omp_for_index (gfor, i)); - tree v = create_tmp_var (type); - gimple_omp_for_set_index (gforo, i, v); - t = unshare_expr (gimple_omp_for_initial (gfor, i)); - gimple_omp_for_set_initial (gforo, i, t); - gimple_omp_for_set_cond (gforo, i, - gimple_omp_for_cond (gfor, i)); - t = unshare_expr (gimple_omp_for_final (gfor, i)); - gimple_omp_for_set_final (gforo, i, t); - t = unshare_expr (gimple_omp_for_incr (gfor, i)); - gcc_assert (TREE_OPERAND (t, 0) == gimple_omp_for_index (gfor, i)); - TREE_OPERAND (t, 0) = v; - gimple_omp_for_set_incr (gforo, i, t); - t = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_DECL (t) = v; - OMP_CLAUSE_CHAIN (t) = gimple_omp_for_clauses (gforo); - gimple_omp_for_set_clauses (gforo, t); - if (OMP_FOR_NON_RECTANGULAR (for_stmt)) - { - tree *p1 = NULL, *p2 = NULL; - t = gimple_omp_for_initial (gforo, i); - if (TREE_CODE (t) == TREE_VEC) - p1 = &TREE_VEC_ELT (t, 0); - t = gimple_omp_for_final (gforo, i); - if (TREE_CODE (t) == TREE_VEC) - { - if (p1) - p2 = &TREE_VEC_ELT (t, 0); - else - p1 = &TREE_VEC_ELT (t, 0); - } - if (p1) - { - int j; - for (j = 0; j < i; j++) - if (*p1 == gimple_omp_for_index (gfor, j)) - { - *p1 = gimple_omp_for_index (gforo, j); - if (p2) - *p2 = *p1; - break; - } - gcc_assert (j < i); - } - } - } - gimplify_seq_add_stmt (pre_p, gforo); - } - else - gimplify_seq_add_stmt (pre_p, gfor); - - if (TREE_CODE (orig_for_stmt) == OMP_FOR) - { - struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - unsigned lastprivate_conditional = 0; - while (ctx - && (ctx->region_type == ORT_TARGET_DATA - || ctx->region_type == ORT_TASKGROUP)) - ctx = ctx->outer_context; - if (ctx && (ctx->region_type & ORT_PARALLEL) != 0) - for (tree c = gimple_omp_for_clauses (gfor); - c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - ++lastprivate_conditional; - if (lastprivate_conditional) - { - struct omp_for_data fd; - omp_extract_for_data (gfor, &fd, NULL); - tree type = build_array_type_nelts (unsigned_type_for (fd.iter_type), - lastprivate_conditional); - tree var = create_tmp_var_raw (type); - tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__CONDTEMP_); - OMP_CLAUSE_DECL (c) = var; - OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (gfor); - gimple_omp_for_set_clauses (gfor, c); - omp_add_variable (ctx, var, GOVD_CONDTEMP | GOVD_SEEN); - } - } - else if (TREE_CODE (orig_for_stmt) == OMP_SIMD) - { - unsigned lastprivate_conditional = 0; - for (tree c = gimple_omp_for_clauses (gfor); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - ++lastprivate_conditional; - if (lastprivate_conditional) - { - struct omp_for_data fd; - omp_extract_for_data (gfor, &fd, NULL); - tree type = unsigned_type_for (fd.iter_type); - while (lastprivate_conditional--) - { - tree c = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE__CONDTEMP_); - OMP_CLAUSE_DECL (c) = create_tmp_var (type); - OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (gfor); - gimple_omp_for_set_clauses (gfor, c); - } - } - } - - if (ret != GS_ALL_DONE) - return GS_ERROR; - *expr_p = NULL_TREE; - return GS_ALL_DONE; -} - -/* Helper for gimplify_omp_loop, called through walk_tree. */ - -static tree -note_no_context_vars (tree *tp, int *, void *data) -{ - if (VAR_P (*tp) - && DECL_CONTEXT (*tp) == NULL_TREE - && !is_global_var (*tp)) - { - vec<tree> *d = (vec<tree> *) data; - d->safe_push (*tp); - DECL_CONTEXT (*tp) = current_function_decl; - } - return NULL_TREE; -} - -/* Gimplify the gross structure of an OMP_LOOP statement. */ - -static enum gimplify_status -gimplify_omp_loop (tree *expr_p, gimple_seq *pre_p) -{ - tree for_stmt = *expr_p; - tree clauses = OMP_FOR_CLAUSES (for_stmt); - struct gimplify_omp_ctx *octx = gimplify_omp_ctxp; - enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD; - int i; - - /* If order is not present, the behavior is as if order(concurrent) - appeared. */ - tree order = omp_find_clause (clauses, OMP_CLAUSE_ORDER); - if (order == NULL_TREE) - { - order = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_ORDER); - OMP_CLAUSE_CHAIN (order) = clauses; - OMP_FOR_CLAUSES (for_stmt) = clauses = order; - } - - tree bind = omp_find_clause (clauses, OMP_CLAUSE_BIND); - if (bind == NULL_TREE) - { - if (!flag_openmp) /* flag_openmp_simd */ - ; - else if (octx && (octx->region_type & ORT_TEAMS) != 0) - kind = OMP_CLAUSE_BIND_TEAMS; - else if (octx && (octx->region_type & ORT_PARALLEL) != 0) - kind = OMP_CLAUSE_BIND_PARALLEL; - else - { - for (; octx; octx = octx->outer_context) - { - if ((octx->region_type & ORT_ACC) != 0 - || octx->region_type == ORT_NONE - || octx->region_type == ORT_IMPLICIT_TARGET) - continue; - break; - } - if (octx == NULL && !in_omp_construct) - error_at (EXPR_LOCATION (for_stmt), - "%<bind%> clause not specified on a %<loop%> " - "construct not nested inside another OpenMP construct"); - } - bind = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_BIND); - OMP_CLAUSE_CHAIN (bind) = clauses; - OMP_CLAUSE_BIND_KIND (bind) = kind; - OMP_FOR_CLAUSES (for_stmt) = bind; - } - else - switch (OMP_CLAUSE_BIND_KIND (bind)) - { - case OMP_CLAUSE_BIND_THREAD: - break; - case OMP_CLAUSE_BIND_PARALLEL: - if (!flag_openmp) /* flag_openmp_simd */ - { - OMP_CLAUSE_BIND_KIND (bind) = OMP_CLAUSE_BIND_THREAD; - break; - } - for (; octx; octx = octx->outer_context) - if (octx->region_type == ORT_SIMD - && omp_find_clause (octx->clauses, OMP_CLAUSE_BIND) == NULL_TREE) - { - error_at (EXPR_LOCATION (for_stmt), - "%<bind(parallel)%> on a %<loop%> construct nested " - "inside %<simd%> construct"); - OMP_CLAUSE_BIND_KIND (bind) = OMP_CLAUSE_BIND_THREAD; - break; - } - kind = OMP_CLAUSE_BIND_PARALLEL; - break; - case OMP_CLAUSE_BIND_TEAMS: - if (!flag_openmp) /* flag_openmp_simd */ - { - OMP_CLAUSE_BIND_KIND (bind) = OMP_CLAUSE_BIND_THREAD; - break; - } - if ((octx - && octx->region_type != ORT_IMPLICIT_TARGET - && octx->region_type != ORT_NONE - && (octx->region_type & ORT_TEAMS) == 0) - || in_omp_construct) - { - error_at (EXPR_LOCATION (for_stmt), - "%<bind(teams)%> on a %<loop%> region not strictly " - "nested inside of a %<teams%> region"); - OMP_CLAUSE_BIND_KIND (bind) = OMP_CLAUSE_BIND_THREAD; - break; - } - kind = OMP_CLAUSE_BIND_TEAMS; - break; - default: - gcc_unreachable (); - } - - for (tree *pc = &OMP_FOR_CLAUSES (for_stmt); *pc; ) - switch (OMP_CLAUSE_CODE (*pc)) - { - case OMP_CLAUSE_REDUCTION: - if (OMP_CLAUSE_REDUCTION_INSCAN (*pc)) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<inscan%> %<reduction%> clause on " - "%qs construct", "loop"); - OMP_CLAUSE_REDUCTION_INSCAN (*pc) = 0; - } - if (OMP_CLAUSE_REDUCTION_TASK (*pc)) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "invalid %<task%> reduction modifier on construct " - "other than %<parallel%>, %qs or %<sections%>", - lang_GNU_Fortran () ? "do" : "for"); - OMP_CLAUSE_REDUCTION_TASK (*pc) = 0; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - case OMP_CLAUSE_LASTPRIVATE: - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - { - tree t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); - if (OMP_CLAUSE_DECL (*pc) == TREE_OPERAND (t, 0)) - break; - if (OMP_FOR_ORIG_DECLS (for_stmt) - && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), - i)) == TREE_LIST - && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), - i))) - { - tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); - if (OMP_CLAUSE_DECL (*pc) == TREE_PURPOSE (orig)) - break; - } - } - if (i == TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "%<lastprivate%> clause on a %<loop%> construct refers " - "to a variable %qD which is not the loop iterator", - OMP_CLAUSE_DECL (*pc)); - *pc = OMP_CLAUSE_CHAIN (*pc); - break; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - default: - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - } - - TREE_SET_CODE (for_stmt, OMP_SIMD); - - int last; - switch (kind) - { - case OMP_CLAUSE_BIND_THREAD: last = 0; break; - case OMP_CLAUSE_BIND_PARALLEL: last = 1; break; - case OMP_CLAUSE_BIND_TEAMS: last = 2; break; - } - for (int pass = 1; pass <= last; pass++) - { - if (pass == 2) - { - tree bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, - make_node (BLOCK)); - append_to_statement_list (*expr_p, &BIND_EXPR_BODY (bind)); - *expr_p = make_node (OMP_PARALLEL); - TREE_TYPE (*expr_p) = void_type_node; - OMP_PARALLEL_BODY (*expr_p) = bind; - OMP_PARALLEL_COMBINED (*expr_p) = 1; - SET_EXPR_LOCATION (*expr_p, EXPR_LOCATION (for_stmt)); - tree *pc = &OMP_PARALLEL_CLAUSES (*expr_p); - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) - if (OMP_FOR_ORIG_DECLS (for_stmt) - && (TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i)) - == TREE_LIST)) - { - tree elt = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); - if (TREE_PURPOSE (elt) && TREE_VALUE (elt)) - { - *pc = build_omp_clause (UNKNOWN_LOCATION, - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (*pc) = TREE_VALUE (elt); - pc = &OMP_CLAUSE_CHAIN (*pc); - } - } - } - tree t = make_node (pass == 2 ? OMP_DISTRIBUTE : OMP_FOR); - tree *pc = &OMP_FOR_CLAUSES (t); - TREE_TYPE (t) = void_type_node; - OMP_FOR_BODY (t) = *expr_p; - SET_EXPR_LOCATION (t, EXPR_LOCATION (for_stmt)); - for (tree c = OMP_FOR_CLAUSES (for_stmt); c; c = OMP_CLAUSE_CHAIN (c)) - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_BIND: - case OMP_CLAUSE_ORDER: - case OMP_CLAUSE_COLLAPSE: - *pc = copy_node (c); - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_FIRSTPRIVATE: - /* Only needed on innermost. */ - break; - case OMP_CLAUSE_LASTPRIVATE: - if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c) && pass != last) - { - *pc = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_FIRSTPRIVATE); - OMP_CLAUSE_DECL (*pc) = OMP_CLAUSE_DECL (c); - lang_hooks.decls.omp_finish_clause (*pc, NULL, false); - pc = &OMP_CLAUSE_CHAIN (*pc); - } - *pc = copy_node (c); - OMP_CLAUSE_LASTPRIVATE_STMT (*pc) = NULL_TREE; - TREE_TYPE (*pc) = unshare_expr (TREE_TYPE (c)); - if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c)) - { - if (pass != last) - OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (*pc) = 1; - else - lang_hooks.decls.omp_finish_clause (*pc, NULL, false); - OMP_CLAUSE_LASTPRIVATE_LOOP_IV (*pc) = 0; - } - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - case OMP_CLAUSE_REDUCTION: - *pc = copy_node (c); - OMP_CLAUSE_DECL (*pc) = unshare_expr (OMP_CLAUSE_DECL (c)); - TREE_TYPE (*pc) = unshare_expr (TREE_TYPE (c)); - if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (*pc)) - { - auto_vec<tree> no_context_vars; - int walk_subtrees = 0; - note_no_context_vars (&OMP_CLAUSE_REDUCTION_PLACEHOLDER (c), - &walk_subtrees, &no_context_vars); - if (tree p = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)) - note_no_context_vars (&p, &walk_subtrees, &no_context_vars); - walk_tree_without_duplicates (&OMP_CLAUSE_REDUCTION_INIT (c), - note_no_context_vars, - &no_context_vars); - walk_tree_without_duplicates (&OMP_CLAUSE_REDUCTION_MERGE (c), - note_no_context_vars, - &no_context_vars); - - OMP_CLAUSE_REDUCTION_PLACEHOLDER (*pc) - = copy_node (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)); - if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (*pc)) - OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (*pc) - = copy_node (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)); - - hash_map<tree, tree> decl_map; - decl_map.put (OMP_CLAUSE_DECL (c), OMP_CLAUSE_DECL (c)); - decl_map.put (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c), - OMP_CLAUSE_REDUCTION_PLACEHOLDER (*pc)); - if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (*pc)) - decl_map.put (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), - OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (*pc)); - - copy_body_data id; - memset (&id, 0, sizeof (id)); - id.src_fn = current_function_decl; - id.dst_fn = current_function_decl; - id.src_cfun = cfun; - id.decl_map = &decl_map; - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = true; - id.transform_return_to_modify = false; - id.eh_lp_nr = 0; - walk_tree (&OMP_CLAUSE_REDUCTION_INIT (*pc), copy_tree_body_r, - &id, NULL); - walk_tree (&OMP_CLAUSE_REDUCTION_MERGE (*pc), copy_tree_body_r, - &id, NULL); - - for (tree d : no_context_vars) - { - DECL_CONTEXT (d) = NULL_TREE; - DECL_CONTEXT (*decl_map.get (d)) = NULL_TREE; - } - } - else - { - OMP_CLAUSE_REDUCTION_INIT (*pc) - = unshare_expr (OMP_CLAUSE_REDUCTION_INIT (c)); - OMP_CLAUSE_REDUCTION_MERGE (*pc) - = unshare_expr (OMP_CLAUSE_REDUCTION_MERGE (c)); - } - pc = &OMP_CLAUSE_CHAIN (*pc); - break; - default: - gcc_unreachable (); - } - *pc = NULL_TREE; - *expr_p = t; - } - return gimplify_omp_for (expr_p, pre_p); -} - - -/* Helper function of optimize_target_teams, find OMP_TEAMS inside - of OMP_TARGET's body. */ - -static tree -find_omp_teams (tree *tp, int *walk_subtrees, void *) -{ - *walk_subtrees = 0; - switch (TREE_CODE (*tp)) - { - case OMP_TEAMS: - return *tp; - case BIND_EXPR: - case STATEMENT_LIST: - *walk_subtrees = 1; - break; - default: - break; - } - return NULL_TREE; -} - -/* Helper function of optimize_target_teams, determine if the expression - can be computed safely before the target construct on the host. */ - -static tree -computable_teams_clause (tree *tp, int *walk_subtrees, void *) -{ - splay_tree_node n; - - if (TYPE_P (*tp)) - { - *walk_subtrees = 0; - return NULL_TREE; - } - switch (TREE_CODE (*tp)) - { - case VAR_DECL: - case PARM_DECL: - case RESULT_DECL: - *walk_subtrees = 0; - if (error_operand_p (*tp) - || !INTEGRAL_TYPE_P (TREE_TYPE (*tp)) - || DECL_HAS_VALUE_EXPR_P (*tp) - || DECL_THREAD_LOCAL_P (*tp) - || TREE_SIDE_EFFECTS (*tp) - || TREE_THIS_VOLATILE (*tp)) - return *tp; - if (is_global_var (*tp) - && (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (*tp)) - || lookup_attribute ("omp declare target link", - DECL_ATTRIBUTES (*tp)))) - return *tp; - if (VAR_P (*tp) - && !DECL_SEEN_IN_BIND_EXPR_P (*tp) - && !is_global_var (*tp) - && decl_function_context (*tp) == current_function_decl) - return *tp; - n = splay_tree_lookup (gimplify_omp_ctxp->variables, - (splay_tree_key) *tp); - if (n == NULL) - { - if (gimplify_omp_ctxp->defaultmap[GDMK_SCALAR] & GOVD_FIRSTPRIVATE) - return NULL_TREE; - return *tp; - } - else if (n->value & GOVD_LOCAL) - return *tp; - else if (n->value & GOVD_FIRSTPRIVATE) - return NULL_TREE; - else if ((n->value & (GOVD_MAP | GOVD_MAP_ALWAYS_TO)) - == (GOVD_MAP | GOVD_MAP_ALWAYS_TO)) - return NULL_TREE; - return *tp; - case INTEGER_CST: - if (!INTEGRAL_TYPE_P (TREE_TYPE (*tp))) - return *tp; - return NULL_TREE; - case TARGET_EXPR: - if (TARGET_EXPR_INITIAL (*tp) - || TREE_CODE (TARGET_EXPR_SLOT (*tp)) != VAR_DECL) - return *tp; - return computable_teams_clause (&TARGET_EXPR_SLOT (*tp), - walk_subtrees, NULL); - /* Allow some reasonable subset of integral arithmetics. */ - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case NEGATE_EXPR: - case ABS_EXPR: - case BIT_NOT_EXPR: - case NON_LVALUE_EXPR: - CASE_CONVERT: - if (!INTEGRAL_TYPE_P (TREE_TYPE (*tp))) - return *tp; - return NULL_TREE; - /* And disallow anything else, except for comparisons. */ - default: - if (COMPARISON_CLASS_P (*tp)) - return NULL_TREE; - return *tp; - } -} - -/* Try to determine if the num_teams and/or thread_limit expressions - can have their values determined already before entering the - target construct. - INTEGER_CSTs trivially are, - integral decls that are firstprivate (explicitly or implicitly) - or explicitly map(always, to:) or map(always, tofrom:) on the target - region too, and expressions involving simple arithmetics on those - too, function calls are not ok, dereferencing something neither etc. - Add NUM_TEAMS and THREAD_LIMIT clauses to the OMP_CLAUSES of - EXPR based on what we find: - 0 stands for clause not specified at all, use implementation default - -1 stands for value that can't be determined easily before entering - the target construct. - If teams construct is not present at all, use 1 for num_teams - and 0 for thread_limit (only one team is involved, and the thread - limit is implementation defined. */ - -static void -optimize_target_teams (tree target, gimple_seq *pre_p) -{ - tree body = OMP_BODY (target); - tree teams = walk_tree (&body, find_omp_teams, NULL, NULL); - tree num_teams_lower = NULL_TREE; - tree num_teams_upper = integer_zero_node; - tree thread_limit = integer_zero_node; - location_t num_teams_loc = EXPR_LOCATION (target); - location_t thread_limit_loc = EXPR_LOCATION (target); - tree c, *p, expr; - struct gimplify_omp_ctx *target_ctx = gimplify_omp_ctxp; - - if (teams == NULL_TREE) - num_teams_upper = integer_one_node; - else - for (c = OMP_TEAMS_CLAUSES (teams); c; c = OMP_CLAUSE_CHAIN (c)) - { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS) - { - p = &num_teams_upper; - num_teams_loc = OMP_CLAUSE_LOCATION (c); - if (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c)) - { - expr = OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c); - if (TREE_CODE (expr) == INTEGER_CST) - num_teams_lower = expr; - else if (walk_tree (&expr, computable_teams_clause, - NULL, NULL)) - num_teams_lower = integer_minus_one_node; - else - { - num_teams_lower = expr; - gimplify_omp_ctxp = gimplify_omp_ctxp->outer_context; - if (gimplify_expr (&num_teams_lower, pre_p, NULL, - is_gimple_val, fb_rvalue, false) - == GS_ERROR) - { - gimplify_omp_ctxp = target_ctx; - num_teams_lower = integer_minus_one_node; - } - else - { - gimplify_omp_ctxp = target_ctx; - if (!DECL_P (expr) && TREE_CODE (expr) != TARGET_EXPR) - OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) - = num_teams_lower; - } - } - } - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) - { - p = &thread_limit; - thread_limit_loc = OMP_CLAUSE_LOCATION (c); - } - else - continue; - expr = OMP_CLAUSE_OPERAND (c, 0); - if (TREE_CODE (expr) == INTEGER_CST) - { - *p = expr; - continue; - } - if (walk_tree (&expr, computable_teams_clause, NULL, NULL)) - { - *p = integer_minus_one_node; - continue; - } - *p = expr; - gimplify_omp_ctxp = gimplify_omp_ctxp->outer_context; - if (gimplify_expr (p, pre_p, NULL, is_gimple_val, fb_rvalue, false) - == GS_ERROR) - { - gimplify_omp_ctxp = target_ctx; - *p = integer_minus_one_node; - continue; - } - gimplify_omp_ctxp = target_ctx; - if (!DECL_P (expr) && TREE_CODE (expr) != TARGET_EXPR) - OMP_CLAUSE_OPERAND (c, 0) = *p; - } - if (!omp_find_clause (OMP_TARGET_CLAUSES (target), OMP_CLAUSE_THREAD_LIMIT)) - { - c = build_omp_clause (thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); - OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = thread_limit; - OMP_CLAUSE_CHAIN (c) = OMP_TARGET_CLAUSES (target); - OMP_TARGET_CLAUSES (target) = c; - } - c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); - OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = num_teams_upper; - OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = num_teams_lower; - OMP_CLAUSE_CHAIN (c) = OMP_TARGET_CLAUSES (target); - OMP_TARGET_CLAUSES (target) = c; -} - -/* Gimplify the gross structure of several OMP constructs. */ - -static void -gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - gimple *stmt; - gimple_seq body = NULL; - enum omp_region_type ort; - - switch (TREE_CODE (expr)) - { - case OMP_SECTIONS: - case OMP_SINGLE: - ort = ORT_WORKSHARE; - break; - case OMP_SCOPE: - ort = ORT_TASKGROUP; - break; - case OMP_TARGET: - ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET; - break; - case OACC_KERNELS: - ort = ORT_ACC_KERNELS; - break; - case OACC_PARALLEL: - ort = ORT_ACC_PARALLEL; - break; - case OACC_SERIAL: - ort = ORT_ACC_SERIAL; - break; - case OACC_DATA: - ort = ORT_ACC_DATA; - break; - case OMP_TARGET_DATA: - ort = ORT_TARGET_DATA; - break; - case OMP_TEAMS: - ort = OMP_TEAMS_COMBINED (expr) ? ORT_COMBINED_TEAMS : ORT_TEAMS; - if (gimplify_omp_ctxp == NULL - || gimplify_omp_ctxp->region_type == ORT_IMPLICIT_TARGET) - ort = (enum omp_region_type) (ort | ORT_HOST_TEAMS); - break; - case OACC_HOST_DATA: - ort = ORT_ACC_HOST_DATA; - break; - default: - gcc_unreachable (); - } - - bool save_in_omp_construct = in_omp_construct; - if ((ort & ORT_ACC) == 0) - in_omp_construct = false; - gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort, - TREE_CODE (expr)); - if (TREE_CODE (expr) == OMP_TARGET) - optimize_target_teams (expr, pre_p); - if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0 - || (ort & ORT_HOST_TEAMS) == ORT_HOST_TEAMS) - { - push_gimplify_context (); - gimple *g = gimplify_and_return_first (OMP_BODY (expr), &body); - if (gimple_code (g) == GIMPLE_BIND) - pop_gimplify_context (g); - else - pop_gimplify_context (NULL); - if ((ort & ORT_TARGET_DATA) != 0) - { - enum built_in_function end_ix; - switch (TREE_CODE (expr)) - { - case OACC_DATA: - case OACC_HOST_DATA: - end_ix = BUILT_IN_GOACC_DATA_END; - break; - case OMP_TARGET_DATA: - end_ix = BUILT_IN_GOMP_TARGET_END_DATA; - break; - default: - gcc_unreachable (); - } - tree fn = builtin_decl_explicit (end_ix); - g = gimple_build_call (fn, 0); - gimple_seq cleanup = NULL; - gimple_seq_add_stmt (&cleanup, g); - g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY); - body = NULL; - gimple_seq_add_stmt (&body, g); - } - } - else - gimplify_and_add (OMP_BODY (expr), &body); - gimplify_adjust_omp_clauses (pre_p, body, &OMP_CLAUSES (expr), - TREE_CODE (expr)); - in_omp_construct = save_in_omp_construct; - - switch (TREE_CODE (expr)) - { - case OACC_DATA: - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_DATA, - OMP_CLAUSES (expr)); - break; - case OACC_HOST_DATA: - if (omp_find_clause (OMP_CLAUSES (expr), OMP_CLAUSE_IF_PRESENT)) - { - for (tree c = OMP_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR) - OMP_CLAUSE_USE_DEVICE_PTR_IF_PRESENT (c) = 1; - } - - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_HOST_DATA, - OMP_CLAUSES (expr)); - break; - case OACC_KERNELS: - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_KERNELS, - OMP_CLAUSES (expr)); - break; - case OACC_PARALLEL: - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_PARALLEL, - OMP_CLAUSES (expr)); - break; - case OACC_SERIAL: - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_SERIAL, - OMP_CLAUSES (expr)); - break; - case OMP_SECTIONS: - stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); - break; - case OMP_SINGLE: - stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); - break; - case OMP_SCOPE: - stmt = gimple_build_omp_scope (body, OMP_CLAUSES (expr)); - break; - case OMP_TARGET: - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, - OMP_CLAUSES (expr)); - break; - case OMP_TARGET_DATA: - /* Put use_device_{ptr,addr} clauses last, as map clauses are supposed - to be evaluated before the use_device_{ptr,addr} clauses if they - refer to the same variables. */ - { - tree use_device_clauses; - tree *pc, *uc = &use_device_clauses; - for (pc = &OMP_CLAUSES (expr); *pc; ) - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR - || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR) - { - *uc = *pc; - *pc = OMP_CLAUSE_CHAIN (*pc); - uc = &OMP_CLAUSE_CHAIN (*uc); - } - else - pc = &OMP_CLAUSE_CHAIN (*pc); - *uc = NULL_TREE; - *pc = use_device_clauses; - stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_DATA, - OMP_CLAUSES (expr)); - } - break; - case OMP_TEAMS: - stmt = gimple_build_omp_teams (body, OMP_CLAUSES (expr)); - if ((ort & ORT_HOST_TEAMS) == ORT_HOST_TEAMS) - gimple_omp_teams_set_host (as_a <gomp_teams *> (stmt), true); - break; - default: - gcc_unreachable (); - } - - gimplify_seq_add_stmt (pre_p, stmt); - *expr_p = NULL_TREE; -} - -/* Gimplify the gross structure of OpenACC enter/exit data, update, and OpenMP - target update constructs. */ - -static void -gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p; - int kind; - gomp_target *stmt; - enum omp_region_type ort = ORT_WORKSHARE; - - switch (TREE_CODE (expr)) - { - case OACC_ENTER_DATA: - kind = GF_OMP_TARGET_KIND_OACC_ENTER_DATA; - ort = ORT_ACC; - break; - case OACC_EXIT_DATA: - kind = GF_OMP_TARGET_KIND_OACC_EXIT_DATA; - ort = ORT_ACC; - break; - case OACC_UPDATE: - kind = GF_OMP_TARGET_KIND_OACC_UPDATE; - ort = ORT_ACC; - break; - case OMP_TARGET_UPDATE: - kind = GF_OMP_TARGET_KIND_UPDATE; - break; - case OMP_TARGET_ENTER_DATA: - kind = GF_OMP_TARGET_KIND_ENTER_DATA; - break; - case OMP_TARGET_EXIT_DATA: - kind = GF_OMP_TARGET_KIND_EXIT_DATA; - break; - default: - gcc_unreachable (); - } - gimplify_scan_omp_clauses (&OMP_STANDALONE_CLAUSES (expr), pre_p, - ort, TREE_CODE (expr)); - gimplify_adjust_omp_clauses (pre_p, NULL, &OMP_STANDALONE_CLAUSES (expr), - TREE_CODE (expr)); - if (TREE_CODE (expr) == OACC_UPDATE - && omp_find_clause (OMP_STANDALONE_CLAUSES (expr), - OMP_CLAUSE_IF_PRESENT)) - { - /* The runtime uses GOMP_MAP_{TO,FROM} to denote the if_present - clause. */ - for (tree c = OMP_STANDALONE_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (c)) - { - case GOMP_MAP_FORCE_TO: - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TO); - break; - case GOMP_MAP_FORCE_FROM: - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FROM); - break; - default: - break; - } - } - else if (TREE_CODE (expr) == OACC_EXIT_DATA - && omp_find_clause (OMP_STANDALONE_CLAUSES (expr), - OMP_CLAUSE_FINALIZE)) - { - /* Use GOMP_MAP_DELETE/GOMP_MAP_FORCE_FROM to denote "finalize" - semantics. */ - bool have_clause = false; - for (tree c = OMP_STANDALONE_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) - switch (OMP_CLAUSE_MAP_KIND (c)) - { - case GOMP_MAP_FROM: - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FORCE_FROM); - have_clause = true; - break; - case GOMP_MAP_RELEASE: - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_DELETE); - have_clause = true; - break; - case GOMP_MAP_TO_PSET: - /* Fortran arrays with descriptors must map that descriptor when - doing standalone "attach" operations (in OpenACC). In that - case GOMP_MAP_TO_PSET appears by itself with no preceding - clause (see trans-openmp.c:gfc_trans_omp_clauses). */ - break; - case GOMP_MAP_POINTER: - /* TODO PR92929: we may see these here, but they'll always follow - one of the clauses above, and will be handled by libgomp as - one group, so no handling required here. */ - gcc_assert (have_clause); - break; - case GOMP_MAP_DETACH: - OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FORCE_DETACH); - have_clause = false; - break; - case GOMP_MAP_STRUCT: - have_clause = false; - break; - default: - gcc_unreachable (); - } - } - stmt = gimple_build_omp_target (NULL, kind, OMP_STANDALONE_CLAUSES (expr)); - - gimplify_seq_add_stmt (pre_p, stmt); - *expr_p = NULL_TREE; -} - -/* A subroutine of gimplify_omp_atomic. The front end is supposed to have - stabilized the lhs of the atomic operation as *ADDR. Return true if - EXPR is this stabilized form. */ - -static bool -goa_lhs_expr_p (tree expr, tree addr) -{ - /* Also include casts to other type variants. The C front end is fond - of adding these for e.g. volatile variables. This is like - STRIP_TYPE_NOPS but includes the main variant lookup. */ - STRIP_USELESS_TYPE_CONVERSION (expr); - - if (TREE_CODE (expr) == INDIRECT_REF) - { - expr = TREE_OPERAND (expr, 0); - while (expr != addr - && (CONVERT_EXPR_P (expr) - || TREE_CODE (expr) == NON_LVALUE_EXPR) - && TREE_CODE (expr) == TREE_CODE (addr) - && types_compatible_p (TREE_TYPE (expr), TREE_TYPE (addr))) - { - expr = TREE_OPERAND (expr, 0); - addr = TREE_OPERAND (addr, 0); - } - if (expr == addr) - return true; - return (TREE_CODE (addr) == ADDR_EXPR - && TREE_CODE (expr) == ADDR_EXPR - && TREE_OPERAND (addr, 0) == TREE_OPERAND (expr, 0)); - } - if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0)) - return true; - return false; -} - -/* Walk *EXPR_P and replace appearances of *LHS_ADDR with LHS_VAR. If an - expression does not involve the lhs, evaluate it into a temporary. - Return 1 if the lhs appeared as a subexpression, 0 if it did not, - or -1 if an error was encountered. */ - -static int -goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, - tree lhs_var, tree &target_expr, bool rhs, int depth) -{ - tree expr = *expr_p; - int saw_lhs = 0; - - if (goa_lhs_expr_p (expr, lhs_addr)) - { - if (pre_p) - *expr_p = lhs_var; - return 1; - } - if (is_gimple_val (expr)) - return 0; - - /* Maximum depth of lhs in expression is for the - __builtin_clear_padding (...), __builtin_clear_padding (...), - __builtin_memcmp (&TARGET_EXPR <lhs, >, ...) == 0 ? ... : lhs; */ - if (++depth > 7) - goto finish; - - switch (TREE_CODE_CLASS (TREE_CODE (expr))) - { - case tcc_binary: - case tcc_comparison: - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr, - lhs_var, target_expr, true, depth); - /* FALLTHRU */ - case tcc_unary: - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr, - lhs_var, target_expr, true, depth); - break; - case tcc_expression: - switch (TREE_CODE (expr)) - { - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case BIT_INSERT_EXPR: - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - /* FALLTHRU */ - case TRUTH_NOT_EXPR: - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - break; - case MODIFY_EXPR: - if (pre_p && !goa_stabilize_expr (expr_p, NULL, lhs_addr, lhs_var, - target_expr, true, depth)) - break; - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var, target_expr, false, - depth); - break; - /* FALLTHRU */ - case ADDR_EXPR: - if (pre_p && !goa_stabilize_expr (expr_p, NULL, lhs_addr, lhs_var, - target_expr, true, depth)) - break; - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var, target_expr, false, - depth); - break; - case COMPOUND_EXPR: - /* Break out any preevaluations from cp_build_modify_expr. */ - for (; TREE_CODE (expr) == COMPOUND_EXPR; - expr = TREE_OPERAND (expr, 1)) - { - /* Special-case __builtin_clear_padding call before - __builtin_memcmp. */ - if (TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR) - { - tree fndecl = get_callee_fndecl (TREE_OPERAND (expr, 0)); - if (fndecl - && fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) - && VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))) - && (!pre_p - || goa_stabilize_expr (&TREE_OPERAND (expr, 0), NULL, - lhs_addr, lhs_var, - target_expr, true, depth))) - { - if (pre_p) - *expr_p = expr; - saw_lhs = goa_stabilize_expr (&TREE_OPERAND (expr, 0), - pre_p, lhs_addr, lhs_var, - target_expr, true, depth); - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), - pre_p, lhs_addr, lhs_var, - target_expr, rhs, depth); - return saw_lhs; - } - } - - if (pre_p) - gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p); - } - if (!pre_p) - return goa_stabilize_expr (&expr, pre_p, lhs_addr, lhs_var, - target_expr, rhs, depth); - *expr_p = expr; - return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var, - target_expr, rhs, depth); - case COND_EXPR: - if (!goa_stabilize_expr (&TREE_OPERAND (expr, 0), NULL, lhs_addr, - lhs_var, target_expr, true, depth)) - break; - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 2), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - break; - case TARGET_EXPR: - if (TARGET_EXPR_INITIAL (expr)) - { - if (pre_p && !goa_stabilize_expr (expr_p, NULL, lhs_addr, - lhs_var, target_expr, true, - depth)) - break; - if (expr == target_expr) - saw_lhs = 1; - else - { - saw_lhs = goa_stabilize_expr (&TARGET_EXPR_INITIAL (expr), - pre_p, lhs_addr, lhs_var, - target_expr, true, depth); - if (saw_lhs && target_expr == NULL_TREE && pre_p) - target_expr = expr; - } - } - break; - default: - break; - } - break; - case tcc_reference: - if (TREE_CODE (expr) == BIT_FIELD_REF - || TREE_CODE (expr) == VIEW_CONVERT_EXPR) - saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var, target_expr, true, - depth); - break; - case tcc_vl_exp: - if (TREE_CODE (expr) == CALL_EXPR) - { - if (tree fndecl = get_callee_fndecl (expr)) - if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) - || fndecl_built_in_p (fndecl, BUILT_IN_MEMCMP)) - { - int nargs = call_expr_nargs (expr); - for (int i = 0; i < nargs; i++) - saw_lhs |= goa_stabilize_expr (&CALL_EXPR_ARG (expr, i), - pre_p, lhs_addr, lhs_var, - target_expr, true, depth); - } - } - break; - default: - break; - } - - finish: - if (saw_lhs == 0 && pre_p) - { - enum gimplify_status gs; - if (TREE_CODE (expr) == CALL_EXPR && VOID_TYPE_P (TREE_TYPE (expr))) - { - gimplify_stmt (&expr, pre_p); - return saw_lhs; - } - else if (rhs) - gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue); - else - gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_lvalue, fb_lvalue); - if (gs != GS_ALL_DONE) - saw_lhs = -1; - } - - return saw_lhs; -} - -/* Gimplify an OMP_ATOMIC statement. */ - -static enum gimplify_status -gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) -{ - tree addr = TREE_OPERAND (*expr_p, 0); - tree rhs = TREE_CODE (*expr_p) == OMP_ATOMIC_READ - ? NULL : TREE_OPERAND (*expr_p, 1); - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); - tree tmp_load; - gomp_atomic_load *loadstmt; - gomp_atomic_store *storestmt; - tree target_expr = NULL_TREE; - - tmp_load = create_tmp_reg (type); - if (rhs - && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load, target_expr, - true, 0) < 0) - return GS_ERROR; - - if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue) - != GS_ALL_DONE) - return GS_ERROR; - - loadstmt = gimple_build_omp_atomic_load (tmp_load, addr, - OMP_ATOMIC_MEMORY_ORDER (*expr_p)); - gimplify_seq_add_stmt (pre_p, loadstmt); - if (rhs) - { - /* BIT_INSERT_EXPR is not valid for non-integral bitfield - representatives. Use BIT_FIELD_REF on the lhs instead. */ - tree rhsarg = rhs; - if (TREE_CODE (rhs) == COND_EXPR) - rhsarg = TREE_OPERAND (rhs, 1); - if (TREE_CODE (rhsarg) == BIT_INSERT_EXPR - && !INTEGRAL_TYPE_P (TREE_TYPE (tmp_load))) - { - tree bitpos = TREE_OPERAND (rhsarg, 2); - tree op1 = TREE_OPERAND (rhsarg, 1); - tree bitsize; - tree tmp_store = tmp_load; - if (TREE_CODE (*expr_p) == OMP_ATOMIC_CAPTURE_OLD) - tmp_store = get_initialized_tmp_var (tmp_load, pre_p); - if (INTEGRAL_TYPE_P (TREE_TYPE (op1))) - bitsize = bitsize_int (TYPE_PRECISION (TREE_TYPE (op1))); - else - bitsize = TYPE_SIZE (TREE_TYPE (op1)); - gcc_assert (TREE_OPERAND (rhsarg, 0) == tmp_load); - tree t = build2_loc (EXPR_LOCATION (rhsarg), - MODIFY_EXPR, void_type_node, - build3_loc (EXPR_LOCATION (rhsarg), - BIT_FIELD_REF, TREE_TYPE (op1), - tmp_store, bitsize, bitpos), op1); - if (TREE_CODE (rhs) == COND_EXPR) - t = build3_loc (EXPR_LOCATION (rhs), COND_EXPR, void_type_node, - TREE_OPERAND (rhs, 0), t, void_node); - gimplify_and_add (t, pre_p); - rhs = tmp_store; - } - bool save_allow_rhs_cond_expr = gimplify_ctxp->allow_rhs_cond_expr; - if (TREE_CODE (rhs) == COND_EXPR) - gimplify_ctxp->allow_rhs_cond_expr = true; - enum gimplify_status gs = gimplify_expr (&rhs, pre_p, NULL, - is_gimple_val, fb_rvalue); - gimplify_ctxp->allow_rhs_cond_expr = save_allow_rhs_cond_expr; - if (gs != GS_ALL_DONE) - return GS_ERROR; - } - - if (TREE_CODE (*expr_p) == OMP_ATOMIC_READ) - rhs = tmp_load; - storestmt - = gimple_build_omp_atomic_store (rhs, OMP_ATOMIC_MEMORY_ORDER (*expr_p)); - if (TREE_CODE (*expr_p) != OMP_ATOMIC_READ && OMP_ATOMIC_WEAK (*expr_p)) - { - gimple_omp_atomic_set_weak (loadstmt); - gimple_omp_atomic_set_weak (storestmt); - } - gimplify_seq_add_stmt (pre_p, storestmt); - switch (TREE_CODE (*expr_p)) - { - case OMP_ATOMIC_READ: - case OMP_ATOMIC_CAPTURE_OLD: - *expr_p = tmp_load; - gimple_omp_atomic_set_need_value (loadstmt); - break; - case OMP_ATOMIC_CAPTURE_NEW: - *expr_p = rhs; - gimple_omp_atomic_set_need_value (storestmt); - break; - default: - *expr_p = NULL; - break; - } - - return GS_ALL_DONE; -} - -/* Gimplify a TRANSACTION_EXPR. This involves gimplification of the - body, and adding some EH bits. */ - -static enum gimplify_status -gimplify_transaction (tree *expr_p, gimple_seq *pre_p) -{ - tree expr = *expr_p, temp, tbody = TRANSACTION_EXPR_BODY (expr); - gimple *body_stmt; - gtransaction *trans_stmt; - gimple_seq body = NULL; - int subcode = 0; - - /* Wrap the transaction body in a BIND_EXPR so we have a context - where to put decls for OMP. */ - if (TREE_CODE (tbody) != BIND_EXPR) - { - tree bind = build3 (BIND_EXPR, void_type_node, NULL, tbody, NULL); - TREE_SIDE_EFFECTS (bind) = 1; - SET_EXPR_LOCATION (bind, EXPR_LOCATION (tbody)); - TRANSACTION_EXPR_BODY (expr) = bind; - } - - push_gimplify_context (); - temp = voidify_wrapper_expr (*expr_p, NULL); - - body_stmt = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body); - pop_gimplify_context (body_stmt); - - trans_stmt = gimple_build_transaction (body); - if (TRANSACTION_EXPR_OUTER (expr)) - subcode = GTMA_IS_OUTER; - else if (TRANSACTION_EXPR_RELAXED (expr)) - subcode = GTMA_IS_RELAXED; - gimple_transaction_set_subcode (trans_stmt, subcode); - - gimplify_seq_add_stmt (pre_p, trans_stmt); - - if (temp) - { - *expr_p = temp; - return GS_OK; - } - - *expr_p = NULL_TREE; - return GS_ALL_DONE; -} - -/* Gimplify an OMP_ORDERED construct. EXPR is the tree version. BODY - is the OMP_BODY of the original EXPR (which has already been - gimplified so it's not present in the EXPR). - - Return the gimplified GIMPLE_OMP_ORDERED tuple. */ - -static gimple * -gimplify_omp_ordered (tree expr, gimple_seq body) -{ - tree c, decls; - int failures = 0; - unsigned int i; - tree source_c = NULL_TREE; - tree sink_c = NULL_TREE; - - if (gimplify_omp_ctxp) - { - for (c = OMP_ORDERED_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && gimplify_omp_ctxp->loop_iter_var.is_empty () - && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK - || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<ordered%> construct with %<depend%> clause must be " - "closely nested inside a loop with %<ordered%> clause " - "with a parameter"); - failures++; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) - { - bool fail = false; - for (decls = OMP_CLAUSE_DECL (c), i = 0; - decls && TREE_CODE (decls) == TREE_LIST; - decls = TREE_CHAIN (decls), ++i) - if (i >= gimplify_omp_ctxp->loop_iter_var.length () / 2) - continue; - else if (TREE_VALUE (decls) - != gimplify_omp_ctxp->loop_iter_var[2 * i]) - { - error_at (OMP_CLAUSE_LOCATION (c), - "variable %qE is not an iteration " - "of outermost loop %d, expected %qE", - TREE_VALUE (decls), i + 1, - gimplify_omp_ctxp->loop_iter_var[2 * i]); - fail = true; - failures++; - } - else - TREE_VALUE (decls) - = gimplify_omp_ctxp->loop_iter_var[2 * i + 1]; - if (!fail && i != gimplify_omp_ctxp->loop_iter_var.length () / 2) - { - error_at (OMP_CLAUSE_LOCATION (c), - "number of variables in %<depend%> clause with " - "%<sink%> modifier does not match number of " - "iteration variables"); - failures++; - } - sink_c = c; - } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) - { - if (source_c) - { - error_at (OMP_CLAUSE_LOCATION (c), - "more than one %<depend%> clause with %<source%> " - "modifier on an %<ordered%> construct"); - failures++; - } - else - source_c = c; - } - } - if (source_c && sink_c) - { - error_at (OMP_CLAUSE_LOCATION (source_c), - "%<depend%> clause with %<source%> modifier specified " - "together with %<depend%> clauses with %<sink%> modifier " - "on the same construct"); - failures++; - } - - if (failures) - return gimple_build_nop (); - return gimple_build_omp_ordered (body, OMP_ORDERED_CLAUSES (expr)); -} - -/* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the - expression produces a value to be used as an operand inside a GIMPLE - statement, the value will be stored back in *EXPR_P. This value will - be a tree of class tcc_declaration, tcc_constant, tcc_reference or - an SSA_NAME. The corresponding sequence of GIMPLE statements is - emitted in PRE_P and POST_P. - - Additionally, this process may overwrite parts of the input - expression during gimplification. Ideally, it should be - possible to do non-destructive gimplification. - - EXPR_P points to the GENERIC expression to convert to GIMPLE. If - the expression needs to evaluate to a value to be used as - an operand in a GIMPLE statement, this value will be stored in - *EXPR_P on exit. This happens when the caller specifies one - of fb_lvalue or fb_rvalue fallback flags. - - PRE_P will contain the sequence of GIMPLE statements corresponding - to the evaluation of EXPR and all the side-effects that must - be executed before the main expression. On exit, the last - statement of PRE_P is the core statement being gimplified. For - instance, when gimplifying 'if (++a)' the last statement in - PRE_P will be 'if (t.1)' where t.1 is the result of - pre-incrementing 'a'. - - POST_P will contain the sequence of GIMPLE statements corresponding - to the evaluation of all the side-effects that must be executed - after the main expression. If this is NULL, the post - side-effects are stored at the end of PRE_P. - - The reason why the output is split in two is to handle post - side-effects explicitly. In some cases, an expression may have - inner and outer post side-effects which need to be emitted in - an order different from the one given by the recursive - traversal. For instance, for the expression (*p--)++ the post - side-effects of '--' must actually occur *after* the post - side-effects of '++'. However, gimplification will first visit - the inner expression, so if a separate POST sequence was not - used, the resulting sequence would be: - - 1 t.1 = *p - 2 p = p - 1 - 3 t.2 = t.1 + 1 - 4 *p = t.2 - - However, the post-decrement operation in line #2 must not be - evaluated until after the store to *p at line #4, so the - correct sequence should be: - - 1 t.1 = *p - 2 t.2 = t.1 + 1 - 3 *p = t.2 - 4 p = p - 1 - - So, by specifying a separate post queue, it is possible - to emit the post side-effects in the correct order. - If POST_P is NULL, an internal queue will be used. Before - returning to the caller, the sequence POST_P is appended to - the main output sequence PRE_P. - - GIMPLE_TEST_F points to a function that takes a tree T and - returns nonzero if T is in the GIMPLE form requested by the - caller. The GIMPLE predicates are in gimple.c. - - FALLBACK tells the function what sort of a temporary we want if - gimplification cannot produce an expression that complies with - GIMPLE_TEST_F. - - fb_none means that no temporary should be generated - fb_rvalue means that an rvalue is OK to generate - fb_lvalue means that an lvalue is OK to generate - fb_either means that either is OK, but an lvalue is preferable. - fb_mayfail means that gimplification may fail (in which case - GS_ERROR will be returned) - - The return value is either GS_ERROR or GS_ALL_DONE, since this - function iterates until EXPR is completely gimplified or an error - occurs. */ - -enum gimplify_status -gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool (*gimple_test_f) (tree), fallback_t fallback) -{ - tree tmp; - gimple_seq internal_pre = NULL; - gimple_seq internal_post = NULL; - tree save_expr; - bool is_statement; - location_t saved_location; - enum gimplify_status ret; - gimple_stmt_iterator pre_last_gsi, post_last_gsi; - tree label; - - save_expr = *expr_p; - if (save_expr == NULL_TREE) - return GS_ALL_DONE; - - /* If we are gimplifying a top-level statement, PRE_P must be valid. */ - is_statement = gimple_test_f == is_gimple_stmt; - if (is_statement) - gcc_assert (pre_p); - - /* Consistency checks. */ - if (gimple_test_f == is_gimple_reg) - gcc_assert (fallback & (fb_rvalue | fb_lvalue)); - else if (gimple_test_f == is_gimple_val - || gimple_test_f == is_gimple_call_addr - || gimple_test_f == is_gimple_condexpr - || gimple_test_f == is_gimple_condexpr_for_cond - || gimple_test_f == is_gimple_mem_rhs - || gimple_test_f == is_gimple_mem_rhs_or_call - || gimple_test_f == is_gimple_reg_rhs - || gimple_test_f == is_gimple_reg_rhs_or_call - || gimple_test_f == is_gimple_asm_val - || gimple_test_f == is_gimple_mem_ref_addr) - gcc_assert (fallback & fb_rvalue); - else if (gimple_test_f == is_gimple_min_lval - || gimple_test_f == is_gimple_lvalue) - gcc_assert (fallback & fb_lvalue); - else if (gimple_test_f == is_gimple_addressable) - gcc_assert (fallback & fb_either); - else if (gimple_test_f == is_gimple_stmt) - gcc_assert (fallback == fb_none); - else - { - /* We should have recognized the GIMPLE_TEST_F predicate to - know what kind of fallback to use in case a temporary is - needed to hold the value or address of *EXPR_P. */ - gcc_unreachable (); - } - - /* We used to check the predicate here and return immediately if it - succeeds. This is wrong; the design is for gimplification to be - idempotent, and for the predicates to only test for valid forms, not - whether they are fully simplified. */ - if (pre_p == NULL) - pre_p = &internal_pre; - - if (post_p == NULL) - post_p = &internal_post; - - /* Remember the last statements added to PRE_P and POST_P. Every - new statement added by the gimplification helpers needs to be - annotated with location information. To centralize the - responsibility, we remember the last statement that had been - added to both queues before gimplifying *EXPR_P. If - gimplification produces new statements in PRE_P and POST_P, those - statements will be annotated with the same location information - as *EXPR_P. */ - pre_last_gsi = gsi_last (*pre_p); - post_last_gsi = gsi_last (*post_p); - - saved_location = input_location; - if (save_expr != error_mark_node - && EXPR_HAS_LOCATION (*expr_p)) - input_location = EXPR_LOCATION (*expr_p); - - /* Loop over the specific gimplifiers until the toplevel node - remains the same. */ - do - { - /* Strip away as many useless type conversions as possible - at the toplevel. */ - STRIP_USELESS_TYPE_CONVERSION (*expr_p); - - /* Remember the expr. */ - save_expr = *expr_p; - - /* Die, die, die, my darling. */ - if (error_operand_p (save_expr)) - { - ret = GS_ERROR; - break; - } - - /* Do any language-specific gimplification. */ - ret = ((enum gimplify_status) - lang_hooks.gimplify_expr (expr_p, pre_p, post_p)); - if (ret == GS_OK) - { - if (*expr_p == NULL_TREE) - break; - if (*expr_p != save_expr) - continue; - } - else if (ret != GS_UNHANDLED) - break; - - /* Make sure that all the cases set 'ret' appropriately. */ - ret = GS_UNHANDLED; - switch (TREE_CODE (*expr_p)) - { - /* First deal with the special cases. */ - - case POSTINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: - ret = gimplify_self_mod_expr (expr_p, pre_p, post_p, - fallback != fb_none, - TREE_TYPE (*expr_p)); - break; - - case VIEW_CONVERT_EXPR: - if ((fallback & fb_rvalue) - && is_gimple_reg_type (TREE_TYPE (*expr_p)) - && is_gimple_reg_type (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))) - { - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_val, fb_rvalue); - recalculate_side_effects (*expr_p); - break; - } - /* Fallthru. */ - - case ARRAY_REF: - case ARRAY_RANGE_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - case COMPONENT_REF: - ret = gimplify_compound_lval (expr_p, pre_p, post_p, - fallback ? fallback : fb_rvalue); - break; - - case COND_EXPR: - ret = gimplify_cond_expr (expr_p, pre_p, fallback); - - /* C99 code may assign to an array in a structure value of a - conditional expression, and this has undefined behavior - only on execution, so create a temporary if an lvalue is - required. */ - if (fallback == fb_lvalue) - { - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p, false); - mark_addressable (*expr_p); - ret = GS_OK; - } - break; - - case CALL_EXPR: - ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none); - - /* C99 code may assign to an array in a structure returned - from a function, and this has undefined behavior only on - execution, so create a temporary if an lvalue is - required. */ - if (fallback == fb_lvalue) - { - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p, false); - mark_addressable (*expr_p); - ret = GS_OK; - } - break; - - case TREE_LIST: - gcc_unreachable (); - - case COMPOUND_EXPR: - ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none); - break; - - case COMPOUND_LITERAL_EXPR: - ret = gimplify_compound_literal_expr (expr_p, pre_p, - gimple_test_f, fallback); - break; - - case MODIFY_EXPR: - case INIT_EXPR: - ret = gimplify_modify_expr (expr_p, pre_p, post_p, - fallback != fb_none); - break; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - { - /* Preserve the original type of the expression and the - source location of the outer expression. */ - tree org_type = TREE_TYPE (*expr_p); - *expr_p = gimple_boolify (*expr_p); - *expr_p = build3_loc (input_location, COND_EXPR, - org_type, *expr_p, - fold_convert_loc - (input_location, - org_type, boolean_true_node), - fold_convert_loc - (input_location, - org_type, boolean_false_node)); - ret = GS_OK; - break; - } - - case TRUTH_NOT_EXPR: - { - tree type = TREE_TYPE (*expr_p); - /* The parsers are careful to generate TRUTH_NOT_EXPR - only with operands that are always zero or one. - We do not fold here but handle the only interesting case - manually, as fold may re-introduce the TRUTH_NOT_EXPR. */ - *expr_p = gimple_boolify (*expr_p); - if (TYPE_PRECISION (TREE_TYPE (*expr_p)) == 1) - *expr_p = build1_loc (input_location, BIT_NOT_EXPR, - TREE_TYPE (*expr_p), - TREE_OPERAND (*expr_p, 0)); - else - *expr_p = build2_loc (input_location, BIT_XOR_EXPR, - TREE_TYPE (*expr_p), - TREE_OPERAND (*expr_p, 0), - build_int_cst (TREE_TYPE (*expr_p), 1)); - if (!useless_type_conversion_p (type, TREE_TYPE (*expr_p))) - *expr_p = fold_convert_loc (input_location, type, *expr_p); - ret = GS_OK; - break; - } - - case ADDR_EXPR: - ret = gimplify_addr_expr (expr_p, pre_p, post_p); - break; - - case ANNOTATE_EXPR: - { - tree cond = TREE_OPERAND (*expr_p, 0); - tree kind = TREE_OPERAND (*expr_p, 1); - tree data = TREE_OPERAND (*expr_p, 2); - tree type = TREE_TYPE (cond); - if (!INTEGRAL_TYPE_P (type)) - { - *expr_p = cond; - ret = GS_OK; - break; - } - tree tmp = create_tmp_var (type); - gimplify_arg (&cond, pre_p, EXPR_LOCATION (*expr_p)); - gcall *call - = gimple_build_call_internal (IFN_ANNOTATE, 3, cond, kind, data); - gimple_call_set_lhs (call, tmp); - gimplify_seq_add_stmt (pre_p, call); - *expr_p = tmp; - ret = GS_ALL_DONE; - break; - } - - case VA_ARG_EXPR: - ret = gimplify_va_arg_expr (expr_p, pre_p, post_p); - break; - - CASE_CONVERT: - if (IS_EMPTY_STMT (*expr_p)) - { - ret = GS_ALL_DONE; - break; - } - - if (VOID_TYPE_P (TREE_TYPE (*expr_p)) - || fallback == fb_none) - { - /* Just strip a conversion to void (or in void context) and - try again. */ - *expr_p = TREE_OPERAND (*expr_p, 0); - ret = GS_OK; - break; - } - - ret = gimplify_conversion (expr_p); - if (ret == GS_ERROR) - break; - if (*expr_p != save_expr) - break; - /* FALLTHRU */ - - case FIX_TRUNC_EXPR: - /* unary_expr: ... | '(' cast ')' val | ... */ - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_val, fb_rvalue); - recalculate_side_effects (*expr_p); - break; - - case INDIRECT_REF: - { - bool volatilep = TREE_THIS_VOLATILE (*expr_p); - bool notrap = TREE_THIS_NOTRAP (*expr_p); - tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (*expr_p, 0)); - - *expr_p = fold_indirect_ref_loc (input_location, *expr_p); - if (*expr_p != save_expr) - { - ret = GS_OK; - break; - } - - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_reg, fb_rvalue); - if (ret == GS_ERROR) - break; - - recalculate_side_effects (*expr_p); - *expr_p = fold_build2_loc (input_location, MEM_REF, - TREE_TYPE (*expr_p), - TREE_OPERAND (*expr_p, 0), - build_int_cst (saved_ptr_type, 0)); - TREE_THIS_VOLATILE (*expr_p) = volatilep; - TREE_THIS_NOTRAP (*expr_p) = notrap; - ret = GS_OK; - break; - } - - /* We arrive here through the various re-gimplifcation paths. */ - case MEM_REF: - /* First try re-folding the whole thing. */ - tmp = fold_binary (MEM_REF, TREE_TYPE (*expr_p), - TREE_OPERAND (*expr_p, 0), - TREE_OPERAND (*expr_p, 1)); - if (tmp) - { - REF_REVERSE_STORAGE_ORDER (tmp) - = REF_REVERSE_STORAGE_ORDER (*expr_p); - *expr_p = tmp; - recalculate_side_effects (*expr_p); - ret = GS_OK; - break; - } - /* Avoid re-gimplifying the address operand if it is already - in suitable form. Re-gimplifying would mark the address - operand addressable. Always gimplify when not in SSA form - as we still may have to gimplify decls with value-exprs. */ - if (!gimplify_ctxp || !gimple_in_ssa_p (cfun) - || !is_gimple_mem_ref_addr (TREE_OPERAND (*expr_p, 0))) - { - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_mem_ref_addr, fb_rvalue); - if (ret == GS_ERROR) - break; - } - recalculate_side_effects (*expr_p); - ret = GS_ALL_DONE; - break; - - /* Constants need not be gimplified. */ - case INTEGER_CST: - case REAL_CST: - case FIXED_CST: - case STRING_CST: - case COMPLEX_CST: - case VECTOR_CST: - /* Drop the overflow flag on constants, we do not want - that in the GIMPLE IL. */ - if (TREE_OVERFLOW_P (*expr_p)) - *expr_p = drop_tree_overflow (*expr_p); - ret = GS_ALL_DONE; - break; - - case CONST_DECL: - /* If we require an lvalue, such as for ADDR_EXPR, retain the - CONST_DECL node. Otherwise the decl is replaceable by its - value. */ - /* ??? Should be == fb_lvalue, but ADDR_EXPR passes fb_either. */ - if (fallback & fb_lvalue) - ret = GS_ALL_DONE; - else - { - *expr_p = DECL_INITIAL (*expr_p); - ret = GS_OK; - } - break; - - case DECL_EXPR: - ret = gimplify_decl_expr (expr_p, pre_p); - break; - - case BIND_EXPR: - ret = gimplify_bind_expr (expr_p, pre_p); - break; - - case LOOP_EXPR: - ret = gimplify_loop_expr (expr_p, pre_p); - break; - - case SWITCH_EXPR: - ret = gimplify_switch_expr (expr_p, pre_p); - break; - - case EXIT_EXPR: - ret = gimplify_exit_expr (expr_p); - break; - - case GOTO_EXPR: - /* If the target is not LABEL, then it is a computed jump - and the target needs to be gimplified. */ - if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL) - { - ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p, - NULL, is_gimple_val, fb_rvalue); - if (ret == GS_ERROR) - break; - } - gimplify_seq_add_stmt (pre_p, - gimple_build_goto (GOTO_DESTINATION (*expr_p))); - ret = GS_ALL_DONE; - break; - - case PREDICT_EXPR: - gimplify_seq_add_stmt (pre_p, - gimple_build_predict (PREDICT_EXPR_PREDICTOR (*expr_p), - PREDICT_EXPR_OUTCOME (*expr_p))); - ret = GS_ALL_DONE; - break; - - case LABEL_EXPR: - ret = gimplify_label_expr (expr_p, pre_p); - label = LABEL_EXPR_LABEL (*expr_p); - gcc_assert (decl_function_context (label) == current_function_decl); - - /* If the label is used in a goto statement, or address of the label - is taken, we need to unpoison all variables that were seen so far. - Doing so would prevent us from reporting a false positives. */ - if (asan_poisoned_variables - && asan_used_labels != NULL - && asan_used_labels->contains (label) - && !gimplify_omp_ctxp) - asan_poison_variables (asan_poisoned_variables, false, pre_p); - break; - - case CASE_LABEL_EXPR: - ret = gimplify_case_label_expr (expr_p, pre_p); - - if (gimplify_ctxp->live_switch_vars) - asan_poison_variables (gimplify_ctxp->live_switch_vars, false, - pre_p); - break; - - case RETURN_EXPR: - ret = gimplify_return_expr (*expr_p, pre_p); - break; - - case CONSTRUCTOR: - /* Don't reduce this in place; let gimplify_init_constructor work its - magic. Buf if we're just elaborating this for side effects, just - gimplify any element that has side-effects. */ - if (fallback == fb_none) - { - unsigned HOST_WIDE_INT ix; - tree val; - tree temp = NULL_TREE; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (*expr_p), ix, val) - if (TREE_SIDE_EFFECTS (val)) - append_to_statement_list (val, &temp); - - *expr_p = temp; - ret = temp ? GS_OK : GS_ALL_DONE; - } - /* C99 code may assign to an array in a constructed - structure or union, and this has undefined behavior only - on execution, so create a temporary if an lvalue is - required. */ - else if (fallback == fb_lvalue) - { - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p, false); - mark_addressable (*expr_p); - ret = GS_OK; - } - else - ret = GS_ALL_DONE; - break; - - /* The following are special cases that are not handled by the - original GIMPLE grammar. */ - - /* SAVE_EXPR nodes are converted into a GIMPLE identifier and - eliminated. */ - case SAVE_EXPR: - ret = gimplify_save_expr (expr_p, pre_p, post_p); - break; - - case BIT_FIELD_REF: - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_lvalue, fb_either); - recalculate_side_effects (*expr_p); - break; - - case TARGET_MEM_REF: - { - enum gimplify_status r0 = GS_ALL_DONE, r1 = GS_ALL_DONE; - - if (TMR_BASE (*expr_p)) - r0 = gimplify_expr (&TMR_BASE (*expr_p), pre_p, - post_p, is_gimple_mem_ref_addr, fb_either); - if (TMR_INDEX (*expr_p)) - r1 = gimplify_expr (&TMR_INDEX (*expr_p), pre_p, - post_p, is_gimple_val, fb_rvalue); - if (TMR_INDEX2 (*expr_p)) - r1 = gimplify_expr (&TMR_INDEX2 (*expr_p), pre_p, - post_p, is_gimple_val, fb_rvalue); - /* TMR_STEP and TMR_OFFSET are always integer constants. */ - ret = MIN (r0, r1); - } - break; - - case NON_LVALUE_EXPR: - /* This should have been stripped above. */ - gcc_unreachable (); - - case ASM_EXPR: - ret = gimplify_asm_expr (expr_p, pre_p, post_p); - break; - - case TRY_FINALLY_EXPR: - case TRY_CATCH_EXPR: - { - gimple_seq eval, cleanup; - gtry *try_; - - /* Calls to destructors are generated automatically in FINALLY/CATCH - block. They should have location as UNKNOWN_LOCATION. However, - gimplify_call_expr will reset these call stmts to input_location - if it finds stmt's location is unknown. To prevent resetting for - destructors, we set the input_location to unknown. - Note that this only affects the destructor calls in FINALLY/CATCH - block, and will automatically reset to its original value by the - end of gimplify_expr. */ - input_location = UNKNOWN_LOCATION; - eval = cleanup = NULL; - gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval); - if (TREE_CODE (*expr_p) == TRY_FINALLY_EXPR - && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == EH_ELSE_EXPR) - { - gimple_seq n = NULL, e = NULL; - gimplify_and_add (TREE_OPERAND (TREE_OPERAND (*expr_p, 1), - 0), &n); - gimplify_and_add (TREE_OPERAND (TREE_OPERAND (*expr_p, 1), - 1), &e); - if (!gimple_seq_empty_p (n) && !gimple_seq_empty_p (e)) - { - geh_else *stmt = gimple_build_eh_else (n, e); - gimple_seq_add_stmt (&cleanup, stmt); - } - } - else - gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup); - /* Don't create bogus GIMPLE_TRY with empty cleanup. */ - if (gimple_seq_empty_p (cleanup)) - { - gimple_seq_add_seq (pre_p, eval); - ret = GS_ALL_DONE; - break; - } - try_ = gimple_build_try (eval, cleanup, - TREE_CODE (*expr_p) == TRY_FINALLY_EXPR - ? GIMPLE_TRY_FINALLY - : GIMPLE_TRY_CATCH); - if (EXPR_HAS_LOCATION (save_expr)) - gimple_set_location (try_, EXPR_LOCATION (save_expr)); - else if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION) - gimple_set_location (try_, saved_location); - if (TREE_CODE (*expr_p) == TRY_CATCH_EXPR) - gimple_try_set_catch_is_cleanup (try_, - TRY_CATCH_IS_CLEANUP (*expr_p)); - gimplify_seq_add_stmt (pre_p, try_); - ret = GS_ALL_DONE; - break; - } - - case CLEANUP_POINT_EXPR: - ret = gimplify_cleanup_point_expr (expr_p, pre_p); - break; - - case TARGET_EXPR: - ret = gimplify_target_expr (expr_p, pre_p, post_p); - break; - - case CATCH_EXPR: - { - gimple *c; - gimple_seq handler = NULL; - gimplify_and_add (CATCH_BODY (*expr_p), &handler); - c = gimple_build_catch (CATCH_TYPES (*expr_p), handler); - gimplify_seq_add_stmt (pre_p, c); - ret = GS_ALL_DONE; - break; - } - - case EH_FILTER_EXPR: - { - gimple *ehf; - gimple_seq failure = NULL; - - gimplify_and_add (EH_FILTER_FAILURE (*expr_p), &failure); - ehf = gimple_build_eh_filter (EH_FILTER_TYPES (*expr_p), failure); - copy_warning (ehf, *expr_p); - gimplify_seq_add_stmt (pre_p, ehf); - ret = GS_ALL_DONE; - break; - } - - case OBJ_TYPE_REF: - { - enum gimplify_status r0, r1; - r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, - post_p, is_gimple_val, fb_rvalue); - r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, - post_p, is_gimple_val, fb_rvalue); - TREE_SIDE_EFFECTS (*expr_p) = 0; - ret = MIN (r0, r1); - } - break; - - case LABEL_DECL: - /* We get here when taking the address of a label. We mark - the label as "forced"; meaning it can never be removed and - it is a potential target for any computed goto. */ - FORCED_LABEL (*expr_p) = 1; - ret = GS_ALL_DONE; - break; - - case STATEMENT_LIST: - ret = gimplify_statement_list (expr_p, pre_p); - break; - - case WITH_SIZE_EXPR: - { - gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p == &internal_post ? NULL : post_p, - gimple_test_f, fallback); - gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, - is_gimple_val, fb_rvalue); - ret = GS_ALL_DONE; - } - break; - - case VAR_DECL: - case PARM_DECL: - ret = gimplify_var_or_parm_decl (expr_p); - break; - - case RESULT_DECL: - /* When within an OMP context, notice uses of variables. */ - if (gimplify_omp_ctxp) - omp_notice_variable (gimplify_omp_ctxp, *expr_p, true); - ret = GS_ALL_DONE; - break; - - case DEBUG_EXPR_DECL: - gcc_unreachable (); - - case DEBUG_BEGIN_STMT: - gimplify_seq_add_stmt (pre_p, - gimple_build_debug_begin_stmt - (TREE_BLOCK (*expr_p), - EXPR_LOCATION (*expr_p))); - ret = GS_ALL_DONE; - *expr_p = NULL; - break; - - case SSA_NAME: - /* Allow callbacks into the gimplifier during optimization. */ - ret = GS_ALL_DONE; - break; - - case OMP_PARALLEL: - gimplify_omp_parallel (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OMP_TASK: - gimplify_omp_task (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OMP_FOR: - case OMP_SIMD: - case OMP_DISTRIBUTE: - case OMP_TASKLOOP: - case OACC_LOOP: - ret = gimplify_omp_for (expr_p, pre_p); - break; - - case OMP_LOOP: - ret = gimplify_omp_loop (expr_p, pre_p); - break; - - case OACC_CACHE: - gimplify_oacc_cache (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OACC_DECLARE: - gimplify_oacc_declare (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OACC_HOST_DATA: - case OACC_DATA: - case OACC_KERNELS: - case OACC_PARALLEL: - case OACC_SERIAL: - case OMP_SCOPE: - case OMP_SECTIONS: - case OMP_SINGLE: - case OMP_TARGET: - case OMP_TARGET_DATA: - case OMP_TEAMS: - gimplify_omp_workshare (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OACC_ENTER_DATA: - case OACC_EXIT_DATA: - case OACC_UPDATE: - case OMP_TARGET_UPDATE: - case OMP_TARGET_ENTER_DATA: - case OMP_TARGET_EXIT_DATA: - gimplify_omp_target_update (expr_p, pre_p); - ret = GS_ALL_DONE; - break; - - case OMP_SECTION: - case OMP_MASTER: - case OMP_MASKED: - case OMP_ORDERED: - case OMP_CRITICAL: - case OMP_SCAN: - { - gimple_seq body = NULL; - gimple *g; - bool saved_in_omp_construct = in_omp_construct; - - in_omp_construct = true; - gimplify_and_add (OMP_BODY (*expr_p), &body); - in_omp_construct = saved_in_omp_construct; - switch (TREE_CODE (*expr_p)) - { - case OMP_SECTION: - g = gimple_build_omp_section (body); - break; - case OMP_MASTER: - g = gimple_build_omp_master (body); - break; - case OMP_ORDERED: - g = gimplify_omp_ordered (*expr_p, body); - break; - case OMP_MASKED: - gimplify_scan_omp_clauses (&OMP_MASKED_CLAUSES (*expr_p), - pre_p, ORT_WORKSHARE, OMP_MASKED); - gimplify_adjust_omp_clauses (pre_p, body, - &OMP_MASKED_CLAUSES (*expr_p), - OMP_MASKED); - g = gimple_build_omp_masked (body, - OMP_MASKED_CLAUSES (*expr_p)); - break; - case OMP_CRITICAL: - gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p), - pre_p, ORT_WORKSHARE, OMP_CRITICAL); - gimplify_adjust_omp_clauses (pre_p, body, - &OMP_CRITICAL_CLAUSES (*expr_p), - OMP_CRITICAL); - g = gimple_build_omp_critical (body, - OMP_CRITICAL_NAME (*expr_p), - OMP_CRITICAL_CLAUSES (*expr_p)); - break; - case OMP_SCAN: - gimplify_scan_omp_clauses (&OMP_SCAN_CLAUSES (*expr_p), - pre_p, ORT_WORKSHARE, OMP_SCAN); - gimplify_adjust_omp_clauses (pre_p, body, - &OMP_SCAN_CLAUSES (*expr_p), - OMP_SCAN); - g = gimple_build_omp_scan (body, OMP_SCAN_CLAUSES (*expr_p)); - break; - default: - gcc_unreachable (); - } - gimplify_seq_add_stmt (pre_p, g); - ret = GS_ALL_DONE; - break; - } - - case OMP_TASKGROUP: - { - gimple_seq body = NULL; - - tree *pclauses = &OMP_TASKGROUP_CLAUSES (*expr_p); - bool saved_in_omp_construct = in_omp_construct; - gimplify_scan_omp_clauses (pclauses, pre_p, ORT_TASKGROUP, - OMP_TASKGROUP); - gimplify_adjust_omp_clauses (pre_p, NULL, pclauses, OMP_TASKGROUP); - - in_omp_construct = true; - gimplify_and_add (OMP_BODY (*expr_p), &body); - in_omp_construct = saved_in_omp_construct; - gimple_seq cleanup = NULL; - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END); - gimple *g = gimple_build_call (fn, 0); - gimple_seq_add_stmt (&cleanup, g); - g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY); - body = NULL; - gimple_seq_add_stmt (&body, g); - g = gimple_build_omp_taskgroup (body, *pclauses); - gimplify_seq_add_stmt (pre_p, g); - ret = GS_ALL_DONE; - break; - } - - case OMP_ATOMIC: - case OMP_ATOMIC_READ: - case OMP_ATOMIC_CAPTURE_OLD: - case OMP_ATOMIC_CAPTURE_NEW: - ret = gimplify_omp_atomic (expr_p, pre_p); - break; - - case TRANSACTION_EXPR: - ret = gimplify_transaction (expr_p, pre_p); - break; - - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - { - tree orig_type = TREE_TYPE (*expr_p); - tree new_type, xop0, xop1; - *expr_p = gimple_boolify (*expr_p); - new_type = TREE_TYPE (*expr_p); - if (!useless_type_conversion_p (orig_type, new_type)) - { - *expr_p = fold_convert_loc (input_location, orig_type, *expr_p); - ret = GS_OK; - break; - } - - /* Boolified binary truth expressions are semantically equivalent - to bitwise binary expressions. Canonicalize them to the - bitwise variant. */ - switch (TREE_CODE (*expr_p)) - { - case TRUTH_AND_EXPR: - TREE_SET_CODE (*expr_p, BIT_AND_EXPR); - break; - case TRUTH_OR_EXPR: - TREE_SET_CODE (*expr_p, BIT_IOR_EXPR); - break; - case TRUTH_XOR_EXPR: - TREE_SET_CODE (*expr_p, BIT_XOR_EXPR); - break; - default: - break; - } - /* Now make sure that operands have compatible type to - expression's new_type. */ - xop0 = TREE_OPERAND (*expr_p, 0); - xop1 = TREE_OPERAND (*expr_p, 1); - if (!useless_type_conversion_p (new_type, TREE_TYPE (xop0))) - TREE_OPERAND (*expr_p, 0) = fold_convert_loc (input_location, - new_type, - xop0); - if (!useless_type_conversion_p (new_type, TREE_TYPE (xop1))) - TREE_OPERAND (*expr_p, 1) = fold_convert_loc (input_location, - new_type, - xop1); - /* Continue classified as tcc_binary. */ - goto expr_2; - } - - case VEC_COND_EXPR: - goto expr_3; - - case VEC_PERM_EXPR: - /* Classified as tcc_expression. */ - goto expr_3; - - case BIT_INSERT_EXPR: - /* Argument 3 is a constant. */ - goto expr_2; - - case POINTER_PLUS_EXPR: - { - enum gimplify_status r0, r1; - r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_val, fb_rvalue); - r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, - post_p, is_gimple_val, fb_rvalue); - recalculate_side_effects (*expr_p); - ret = MIN (r0, r1); - break; - } - - default: - switch (TREE_CODE_CLASS (TREE_CODE (*expr_p))) - { - case tcc_comparison: - /* Handle comparison of objects of non scalar mode aggregates - with a call to memcmp. It would be nice to only have to do - this for variable-sized objects, but then we'd have to allow - the same nest of reference nodes we allow for MODIFY_EXPR and - that's too complex. - - Compare scalar mode aggregates as scalar mode values. Using - memcmp for them would be very inefficient at best, and is - plain wrong if bitfields are involved. */ - { - tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 1)); - - /* Vector comparisons need no boolification. */ - if (TREE_CODE (type) == VECTOR_TYPE) - goto expr_2; - else if (!AGGREGATE_TYPE_P (type)) - { - tree org_type = TREE_TYPE (*expr_p); - *expr_p = gimple_boolify (*expr_p); - if (!useless_type_conversion_p (org_type, - TREE_TYPE (*expr_p))) - { - *expr_p = fold_convert_loc (input_location, - org_type, *expr_p); - ret = GS_OK; - } - else - goto expr_2; - } - else if (TYPE_MODE (type) != BLKmode) - ret = gimplify_scalar_mode_aggregate_compare (expr_p); - else - ret = gimplify_variable_sized_compare (expr_p); - - break; - } - - /* If *EXPR_P does not need to be special-cased, handle it - according to its class. */ - case tcc_unary: - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_val, fb_rvalue); - break; - - case tcc_binary: - expr_2: - { - enum gimplify_status r0, r1; - - r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_val, fb_rvalue); - r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, - post_p, is_gimple_val, fb_rvalue); - - ret = MIN (r0, r1); - break; - } - - expr_3: - { - enum gimplify_status r0, r1, r2; - - r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, - post_p, is_gimple_val, fb_rvalue); - r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, - post_p, is_gimple_val, fb_rvalue); - r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, - post_p, is_gimple_val, fb_rvalue); - - ret = MIN (MIN (r0, r1), r2); - break; - } - - case tcc_declaration: - case tcc_constant: - ret = GS_ALL_DONE; - goto dont_recalculate; - - default: - gcc_unreachable (); - } - - recalculate_side_effects (*expr_p); - - dont_recalculate: - break; - } - - gcc_assert (*expr_p || ret != GS_OK); - } - while (ret == GS_OK); - - /* If we encountered an error_mark somewhere nested inside, either - stub out the statement or propagate the error back out. */ - if (ret == GS_ERROR) - { - if (is_statement) - *expr_p = NULL; - goto out; - } - - /* This was only valid as a return value from the langhook, which - we handled. Make sure it doesn't escape from any other context. */ - gcc_assert (ret != GS_UNHANDLED); - - if (fallback == fb_none && *expr_p && !is_gimple_stmt (*expr_p)) - { - /* We aren't looking for a value, and we don't have a valid - statement. If it doesn't have side-effects, throw it away. - We can also get here with code such as "*&&L;", where L is - a LABEL_DECL that is marked as FORCED_LABEL. */ - if (TREE_CODE (*expr_p) == LABEL_DECL - || !TREE_SIDE_EFFECTS (*expr_p)) - *expr_p = NULL; - else if (!TREE_THIS_VOLATILE (*expr_p)) - { - /* This is probably a _REF that contains something nested that - has side effects. Recurse through the operands to find it. */ - enum tree_code code = TREE_CODE (*expr_p); - - switch (code) - { - case COMPONENT_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - case VIEW_CONVERT_EXPR: - gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - gimple_test_f, fallback); - break; - - case ARRAY_REF: - case ARRAY_RANGE_REF: - gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - gimple_test_f, fallback); - gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, - gimple_test_f, fallback); - break; - - default: - /* Anything else with side-effects must be converted to - a valid statement before we get here. */ - gcc_unreachable (); - } - - *expr_p = NULL; - } - else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)) - && TYPE_MODE (TREE_TYPE (*expr_p)) != BLKmode - && !is_empty_type (TREE_TYPE (*expr_p))) - { - /* Historically, the compiler has treated a bare reference - to a non-BLKmode volatile lvalue as forcing a load. */ - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p)); - - /* Normally, we do not want to create a temporary for a - TREE_ADDRESSABLE type because such a type should not be - copied by bitwise-assignment. However, we make an - exception here, as all we are doing here is ensuring that - we read the bytes that make up the type. We use - create_tmp_var_raw because create_tmp_var will abort when - given a TREE_ADDRESSABLE type. */ - tree tmp = create_tmp_var_raw (type, "vol"); - gimple_add_tmp_var (tmp); - gimplify_assign (tmp, *expr_p, pre_p); - *expr_p = NULL; - } - else - /* We can't do anything useful with a volatile reference to - an incomplete type, so just throw it away. Likewise for - a BLKmode type, since any implicit inner load should - already have been turned into an explicit one by the - gimplification process. */ - *expr_p = NULL; - } - - /* If we are gimplifying at the statement level, we're done. Tack - everything together and return. */ - if (fallback == fb_none || is_statement) - { - /* Since *EXPR_P has been converted into a GIMPLE tuple, clear - it out for GC to reclaim it. */ - *expr_p = NULL_TREE; - - if (!gimple_seq_empty_p (internal_pre) - || !gimple_seq_empty_p (internal_post)) - { - gimplify_seq_add_seq (&internal_pre, internal_post); - gimplify_seq_add_seq (pre_p, internal_pre); - } - - /* The result of gimplifying *EXPR_P is going to be the last few - statements in *PRE_P and *POST_P. Add location information - to all the statements that were added by the gimplification - helpers. */ - if (!gimple_seq_empty_p (*pre_p)) - annotate_all_with_location_after (*pre_p, pre_last_gsi, input_location); - - if (!gimple_seq_empty_p (*post_p)) - annotate_all_with_location_after (*post_p, post_last_gsi, - input_location); - - goto out; - } - -#ifdef ENABLE_GIMPLE_CHECKING - if (*expr_p) - { - enum tree_code code = TREE_CODE (*expr_p); - /* These expressions should already be in gimple IR form. */ - gcc_assert (code != MODIFY_EXPR - && code != ASM_EXPR - && code != BIND_EXPR - && code != CATCH_EXPR - && (code != COND_EXPR || gimplify_ctxp->allow_rhs_cond_expr) - && code != EH_FILTER_EXPR - && code != GOTO_EXPR - && code != LABEL_EXPR - && code != LOOP_EXPR - && code != SWITCH_EXPR - && code != TRY_FINALLY_EXPR - && code != EH_ELSE_EXPR - && code != OACC_PARALLEL - && code != OACC_KERNELS - && code != OACC_SERIAL - && code != OACC_DATA - && code != OACC_HOST_DATA - && code != OACC_DECLARE - && code != OACC_UPDATE - && code != OACC_ENTER_DATA - && code != OACC_EXIT_DATA - && code != OACC_CACHE - && code != OMP_CRITICAL - && code != OMP_FOR - && code != OACC_LOOP - && code != OMP_MASTER - && code != OMP_MASKED - && code != OMP_TASKGROUP - && code != OMP_ORDERED - && code != OMP_PARALLEL - && code != OMP_SCAN - && code != OMP_SECTIONS - && code != OMP_SECTION - && code != OMP_SINGLE - && code != OMP_SCOPE); - } -#endif - - /* Otherwise we're gimplifying a subexpression, so the resulting - value is interesting. If it's a valid operand that matches - GIMPLE_TEST_F, we're done. Unless we are handling some - post-effects internally; if that's the case, we need to copy into - a temporary before adding the post-effects to POST_P. */ - if (gimple_seq_empty_p (internal_post) && (*gimple_test_f) (*expr_p)) - goto out; - - /* Otherwise, we need to create a new temporary for the gimplified - expression. */ - - /* We can't return an lvalue if we have an internal postqueue. The - object the lvalue refers to would (probably) be modified by the - postqueue; we need to copy the value out first, which means an - rvalue. */ - if ((fallback & fb_lvalue) - && gimple_seq_empty_p (internal_post) - && is_gimple_addressable (*expr_p)) - { - /* An lvalue will do. Take the address of the expression, store it - in a temporary, and replace the expression with an INDIRECT_REF of - that temporary. */ - tree ref_alias_type = reference_alias_ptr_type (*expr_p); - unsigned int ref_align = get_object_alignment (*expr_p); - tree ref_type = TREE_TYPE (*expr_p); - tmp = build_fold_addr_expr_loc (input_location, *expr_p); - gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue); - if (TYPE_ALIGN (ref_type) != ref_align) - ref_type = build_aligned_type (ref_type, ref_align); - *expr_p = build2 (MEM_REF, ref_type, - tmp, build_zero_cst (ref_alias_type)); - } - else if ((fallback & fb_rvalue) && is_gimple_reg_rhs_or_call (*expr_p)) - { - /* An rvalue will do. Assign the gimplified expression into a - new temporary TMP and replace the original expression with - TMP. First, make sure that the expression has a type so that - it can be assigned into a temporary. */ - gcc_assert (!VOID_TYPE_P (TREE_TYPE (*expr_p))); - *expr_p = get_formal_tmp_var (*expr_p, pre_p); - } - else - { -#ifdef ENABLE_GIMPLE_CHECKING - if (!(fallback & fb_mayfail)) - { - fprintf (stderr, "gimplification failed:\n"); - print_generic_expr (stderr, *expr_p); - debug_tree (*expr_p); - internal_error ("gimplification failed"); - } -#endif - gcc_assert (fallback & fb_mayfail); - - /* If this is an asm statement, and the user asked for the - impossible, don't die. Fail and let gimplify_asm_expr - issue an error. */ - ret = GS_ERROR; - goto out; - } - - /* Make sure the temporary matches our predicate. */ - gcc_assert ((*gimple_test_f) (*expr_p)); - - if (!gimple_seq_empty_p (internal_post)) - { - annotate_all_with_location (internal_post, input_location); - gimplify_seq_add_seq (pre_p, internal_post); - } - - out: - input_location = saved_location; - return ret; -} - -/* Like gimplify_expr but make sure the gimplified result is not itself - a SSA name (but a decl if it were). Temporaries required by - evaluating *EXPR_P may be still SSA names. */ - -static enum gimplify_status -gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool (*gimple_test_f) (tree), fallback_t fallback, - bool allow_ssa) -{ - enum gimplify_status ret = gimplify_expr (expr_p, pre_p, post_p, - gimple_test_f, fallback); - if (! allow_ssa - && TREE_CODE (*expr_p) == SSA_NAME) - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL, false); - return ret; -} - -/* Look through TYPE for variable-sized objects and gimplify each such - size that we find. Add to LIST_P any statements generated. */ - -void -gimplify_type_sizes (tree type, gimple_seq *list_p) -{ - if (type == NULL || type == error_mark_node) - return; - - const bool ignored_p - = TYPE_NAME (type) - && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_IGNORED_P (TYPE_NAME (type)); - tree t; - - /* We first do the main variant, then copy into any other variants. */ - type = TYPE_MAIN_VARIANT (type); - - /* Avoid infinite recursion. */ - if (TYPE_SIZES_GIMPLIFIED (type)) - return; - - TYPE_SIZES_GIMPLIFIED (type) = 1; - - switch (TREE_CODE (type)) - { - case INTEGER_TYPE: - case ENUMERAL_TYPE: - case BOOLEAN_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p); - gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p); - - for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) - { - TYPE_MIN_VALUE (t) = TYPE_MIN_VALUE (type); - TYPE_MAX_VALUE (t) = TYPE_MAX_VALUE (type); - } - break; - - case ARRAY_TYPE: - /* These types may not have declarations, so handle them here. */ - gimplify_type_sizes (TREE_TYPE (type), list_p); - gimplify_type_sizes (TYPE_DOMAIN (type), list_p); - /* Ensure VLA bounds aren't removed, for -O0 they should be variables - with assigned stack slots, for -O1+ -g they should be tracked - by VTA. */ - if (!ignored_p - && TYPE_DOMAIN (type) - && INTEGRAL_TYPE_P (TYPE_DOMAIN (type))) - { - t = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - if (t && VAR_P (t) && DECL_ARTIFICIAL (t)) - DECL_IGNORED_P (t) = 0; - t = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - if (t && VAR_P (t) && DECL_ARTIFICIAL (t)) - DECL_IGNORED_P (t) = 0; - } - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL) - { - gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p); - /* Likewise, ensure variable offsets aren't removed. */ - if (!ignored_p - && (t = DECL_FIELD_OFFSET (field)) - && VAR_P (t) - && DECL_ARTIFICIAL (t)) - DECL_IGNORED_P (t) = 0; - gimplify_one_sizepos (&DECL_SIZE (field), list_p); - gimplify_one_sizepos (&DECL_SIZE_UNIT (field), list_p); - gimplify_type_sizes (TREE_TYPE (field), list_p); - } - break; - - case POINTER_TYPE: - case REFERENCE_TYPE: - /* We used to recurse on the pointed-to type here, which turned out to - be incorrect because its definition might refer to variables not - yet initialized at this point if a forward declaration is involved. - - It was actually useful for anonymous pointed-to types to ensure - that the sizes evaluation dominates every possible later use of the - values. Restricting to such types here would be safe since there - is no possible forward declaration around, but would introduce an - undesirable middle-end semantic to anonymity. We then defer to - front-ends the responsibility of ensuring that the sizes are - evaluated both early and late enough, e.g. by attaching artificial - type declarations to the tree. */ - break; - - default: - break; - } - - gimplify_one_sizepos (&TYPE_SIZE (type), list_p); - gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), list_p); - - for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) - { - TYPE_SIZE (t) = TYPE_SIZE (type); - TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type); - TYPE_SIZES_GIMPLIFIED (t) = 1; - } -} - -/* A subroutine of gimplify_type_sizes to make sure that *EXPR_P, - a size or position, has had all of its SAVE_EXPRs evaluated. - We add any required statements to *STMT_P. */ - -void -gimplify_one_sizepos (tree *expr_p, gimple_seq *stmt_p) -{ - tree expr = *expr_p; - - /* We don't do anything if the value isn't there, is constant, or contains - A PLACEHOLDER_EXPR. We also don't want to do anything if it's already - a VAR_DECL. If it's a VAR_DECL from another function, the gimplifier - will want to replace it with a new variable, but that will cause problems - if this type is from outside the function. It's OK to have that here. */ - if (expr == NULL_TREE - || is_gimple_constant (expr) - || TREE_CODE (expr) == VAR_DECL - || CONTAINS_PLACEHOLDER_P (expr)) - return; - - *expr_p = unshare_expr (expr); - - /* SSA names in decl/type fields are a bad idea - they'll get reclaimed - if the def vanishes. */ - gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue, false); - - /* If expr wasn't already is_gimple_sizepos or is_gimple_constant from the - FE, ensure that it is a VAR_DECL, otherwise we might handle some decls - as gimplify_vla_decl even when they would have all sizes INTEGER_CSTs. */ - if (is_gimple_constant (*expr_p)) - *expr_p = get_initialized_tmp_var (*expr_p, stmt_p, NULL, false); -} - -/* Gimplify the body of statements of FNDECL and return a GIMPLE_BIND node - containing the sequence of corresponding GIMPLE statements. If DO_PARMS - is true, also gimplify the parameters. */ - -gbind * -gimplify_body (tree fndecl, bool do_parms) -{ - location_t saved_location = input_location; - gimple_seq parm_stmts, parm_cleanup = NULL, seq; - gimple *outer_stmt; - gbind *outer_bind; - - timevar_push (TV_TREE_GIMPLIFY); - - init_tree_ssa (cfun); - - /* Initialize for optimize_insn_for_s{ize,peed}_p possibly called during - gimplification. */ - default_rtl_profile (); - - gcc_assert (gimplify_ctxp == NULL); - push_gimplify_context (true); - - if (flag_openacc || flag_openmp) - { - gcc_assert (gimplify_omp_ctxp == NULL); - if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl))) - gimplify_omp_ctxp = new_omp_context (ORT_IMPLICIT_TARGET); - } - - /* Unshare most shared trees in the body and in that of any nested functions. - It would seem we don't have to do this for nested functions because - they are supposed to be output and then the outer function gimplified - first, but the g++ front end doesn't always do it that way. */ - unshare_body (fndecl); - unvisit_body (fndecl); - - /* Make sure input_location isn't set to something weird. */ - input_location = DECL_SOURCE_LOCATION (fndecl); - - /* Resolve callee-copies. This has to be done before processing - the body so that DECL_VALUE_EXPR gets processed correctly. */ - parm_stmts = do_parms ? gimplify_parameters (&parm_cleanup) : NULL; - - /* Gimplify the function's body. */ - seq = NULL; - gimplify_stmt (&DECL_SAVED_TREE (fndecl), &seq); - outer_stmt = gimple_seq_first_nondebug_stmt (seq); - if (!outer_stmt) - { - outer_stmt = gimple_build_nop (); - gimplify_seq_add_stmt (&seq, outer_stmt); - } - - /* The body must contain exactly one statement, a GIMPLE_BIND. If this is - not the case, wrap everything in a GIMPLE_BIND to make it so. */ - if (gimple_code (outer_stmt) == GIMPLE_BIND - && (gimple_seq_first_nondebug_stmt (seq) - == gimple_seq_last_nondebug_stmt (seq))) - { - outer_bind = as_a <gbind *> (outer_stmt); - if (gimple_seq_first_stmt (seq) != outer_stmt - || gimple_seq_last_stmt (seq) != outer_stmt) - { - /* If there are debug stmts before or after outer_stmt, move them - inside of outer_bind body. */ - gimple_stmt_iterator gsi = gsi_for_stmt (outer_stmt, &seq); - gimple_seq second_seq = NULL; - if (gimple_seq_first_stmt (seq) != outer_stmt - && gimple_seq_last_stmt (seq) != outer_stmt) - { - second_seq = gsi_split_seq_after (gsi); - gsi_remove (&gsi, false); - } - else if (gimple_seq_first_stmt (seq) != outer_stmt) - gsi_remove (&gsi, false); - else - { - gsi_remove (&gsi, false); - second_seq = seq; - seq = NULL; - } - gimple_seq_add_seq_without_update (&seq, - gimple_bind_body (outer_bind)); - gimple_seq_add_seq_without_update (&seq, second_seq); - gimple_bind_set_body (outer_bind, seq); - } - } - else - outer_bind = gimple_build_bind (NULL_TREE, seq, NULL); - - DECL_SAVED_TREE (fndecl) = NULL_TREE; - - /* If we had callee-copies statements, insert them at the beginning - of the function and clear DECL_VALUE_EXPR_P on the parameters. */ - if (!gimple_seq_empty_p (parm_stmts)) - { - tree parm; - - gimplify_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind)); - if (parm_cleanup) - { - gtry *g = gimple_build_try (parm_stmts, parm_cleanup, - GIMPLE_TRY_FINALLY); - parm_stmts = NULL; - gimple_seq_add_stmt (&parm_stmts, g); - } - gimple_bind_set_body (outer_bind, parm_stmts); - - for (parm = DECL_ARGUMENTS (current_function_decl); - parm; parm = DECL_CHAIN (parm)) - if (DECL_HAS_VALUE_EXPR_P (parm)) - { - DECL_HAS_VALUE_EXPR_P (parm) = 0; - DECL_IGNORED_P (parm) = 0; - } - } - - if ((flag_openacc || flag_openmp || flag_openmp_simd) - && gimplify_omp_ctxp) - { - delete_omp_context (gimplify_omp_ctxp); - gimplify_omp_ctxp = NULL; - } - - pop_gimplify_context (outer_bind); - gcc_assert (gimplify_ctxp == NULL); - - if (flag_checking && !seen_error ()) - verify_gimple_in_seq (gimple_bind_body (outer_bind)); - - timevar_pop (TV_TREE_GIMPLIFY); - input_location = saved_location; - - return outer_bind; -} - -typedef char *char_p; /* For DEF_VEC_P. */ - -/* Return whether we should exclude FNDECL from instrumentation. */ - -static bool -flag_instrument_functions_exclude_p (tree fndecl) -{ - vec<char_p> *v; - - v = (vec<char_p> *) flag_instrument_functions_exclude_functions; - if (v && v->length () > 0) - { - const char *name; - int i; - char *s; - - name = lang_hooks.decl_printable_name (fndecl, 1); - FOR_EACH_VEC_ELT (*v, i, s) - if (strstr (name, s) != NULL) - return true; - } - - v = (vec<char_p> *) flag_instrument_functions_exclude_files; - if (v && v->length () > 0) - { - const char *name; - int i; - char *s; - - name = DECL_SOURCE_FILE (fndecl); - FOR_EACH_VEC_ELT (*v, i, s) - if (strstr (name, s) != NULL) - return true; - } - - return false; -} - -/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL - node for the function we want to gimplify. - - Return the sequence of GIMPLE statements corresponding to the body - of FNDECL. */ - -void -gimplify_function_tree (tree fndecl) -{ - gimple_seq seq; - gbind *bind; - - gcc_assert (!gimple_body (fndecl)); - - if (DECL_STRUCT_FUNCTION (fndecl)) - push_cfun (DECL_STRUCT_FUNCTION (fndecl)); - else - push_struct_function (fndecl); - - /* Tentatively set PROP_gimple_lva here, and reset it in gimplify_va_arg_expr - if necessary. */ - cfun->curr_properties |= PROP_gimple_lva; - - if (asan_sanitize_use_after_scope ()) - asan_poisoned_variables = new hash_set<tree> (); - bind = gimplify_body (fndecl, true); - if (asan_poisoned_variables) - { - delete asan_poisoned_variables; - asan_poisoned_variables = NULL; - } - - /* The tree body of the function is no longer needed, replace it - with the new GIMPLE body. */ - seq = NULL; - gimple_seq_add_stmt (&seq, bind); - gimple_set_body (fndecl, seq); - - /* If we're instrumenting function entry/exit, then prepend the call to - the entry hook and wrap the whole function in a TRY_FINALLY_EXPR to - catch the exit hook. */ - /* ??? Add some way to ignore exceptions for this TFE. */ - if (flag_instrument_function_entry_exit - && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) - /* Do not instrument extern inline functions. */ - && !(DECL_DECLARED_INLINE_P (fndecl) - && DECL_EXTERNAL (fndecl) - && DECL_DISREGARD_INLINE_LIMITS (fndecl)) - && !flag_instrument_functions_exclude_p (fndecl)) - { - tree x; - gbind *new_bind; - gimple *tf; - gimple_seq cleanup = NULL, body = NULL; - tree tmp_var, this_fn_addr; - gcall *call; - - /* The instrumentation hooks aren't going to call the instrumented - function and the address they receive is expected to be matchable - against symbol addresses. Make sure we don't create a trampoline, - in case the current function is nested. */ - this_fn_addr = build_fold_addr_expr (current_function_decl); - TREE_NO_TRAMPOLINE (this_fn_addr) = 1; - - x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS); - call = gimple_build_call (x, 1, integer_zero_node); - tmp_var = create_tmp_var (ptr_type_node, "return_addr"); - gimple_call_set_lhs (call, tmp_var); - gimplify_seq_add_stmt (&cleanup, call); - x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_EXIT); - call = gimple_build_call (x, 2, this_fn_addr, tmp_var); - gimplify_seq_add_stmt (&cleanup, call); - tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY); - - x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS); - call = gimple_build_call (x, 1, integer_zero_node); - tmp_var = create_tmp_var (ptr_type_node, "return_addr"); - gimple_call_set_lhs (call, tmp_var); - gimplify_seq_add_stmt (&body, call); - x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_ENTER); - call = gimple_build_call (x, 2, this_fn_addr, tmp_var); - gimplify_seq_add_stmt (&body, call); - gimplify_seq_add_stmt (&body, tf); - new_bind = gimple_build_bind (NULL, body, NULL); - - /* Replace the current function body with the body - wrapped in the try/finally TF. */ - seq = NULL; - gimple_seq_add_stmt (&seq, new_bind); - gimple_set_body (fndecl, seq); - bind = new_bind; - } - - if (sanitize_flags_p (SANITIZE_THREAD) - && param_tsan_instrument_func_entry_exit) - { - gcall *call = gimple_build_call_internal (IFN_TSAN_FUNC_EXIT, 0); - gimple *tf = gimple_build_try (seq, call, GIMPLE_TRY_FINALLY); - gbind *new_bind = gimple_build_bind (NULL, tf, NULL); - /* Replace the current function body with the body - wrapped in the try/finally TF. */ - seq = NULL; - gimple_seq_add_stmt (&seq, new_bind); - gimple_set_body (fndecl, seq); - } - - DECL_SAVED_TREE (fndecl) = NULL_TREE; - cfun->curr_properties |= PROP_gimple_any; - - pop_cfun (); - - dump_function (TDI_gimple, fndecl); -} - -/* Return a dummy expression of type TYPE in order to keep going after an - error. */ - -static tree -dummy_object (tree type) -{ - tree t = build_int_cst (build_pointer_type (type), 0); - return build2 (MEM_REF, type, t, t); -} - -/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a - builtin function, but a very special sort of operator. */ - -enum gimplify_status -gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, - gimple_seq *post_p ATTRIBUTE_UNUSED) -{ - tree promoted_type, have_va_type; - tree valist = TREE_OPERAND (*expr_p, 0); - tree type = TREE_TYPE (*expr_p); - tree t, tag, aptag; - location_t loc = EXPR_LOCATION (*expr_p); - - /* Verify that valist is of the proper type. */ - have_va_type = TREE_TYPE (valist); - if (have_va_type == error_mark_node) - return GS_ERROR; - have_va_type = targetm.canonical_va_list_type (have_va_type); - if (have_va_type == NULL_TREE - && POINTER_TYPE_P (TREE_TYPE (valist))) - /* Handle 'Case 1: Not an array type' from c-common.c/build_va_arg. */ - have_va_type - = targetm.canonical_va_list_type (TREE_TYPE (TREE_TYPE (valist))); - gcc_assert (have_va_type != NULL_TREE); - - /* Generate a diagnostic for requesting data of a type that cannot - be passed through `...' due to type promotion at the call site. */ - if ((promoted_type = lang_hooks.types.type_promotes_to (type)) - != type) - { - static bool gave_help; - bool warned; - /* Use the expansion point to handle cases such as passing bool (defined - in a system header) through `...'. */ - location_t xloc - = expansion_point_location_if_in_system_header (loc); - - /* Unfortunately, this is merely undefined, rather than a constraint - violation, so we cannot make this an error. If this call is never - executed, the program is still strictly conforming. */ - auto_diagnostic_group d; - warned = warning_at (xloc, 0, - "%qT is promoted to %qT when passed through %<...%>", - type, promoted_type); - if (!gave_help && warned) - { - gave_help = true; - inform (xloc, "(so you should pass %qT not %qT to %<va_arg%>)", - promoted_type, type); - } - - /* We can, however, treat "undefined" any way we please. - Call abort to encourage the user to fix the program. */ - if (warned) - inform (xloc, "if this code is reached, the program will abort"); - /* Before the abort, allow the evaluation of the va_list - expression to exit or longjmp. */ - gimplify_and_add (valist, pre_p); - t = build_call_expr_loc (loc, - builtin_decl_implicit (BUILT_IN_TRAP), 0); - gimplify_and_add (t, pre_p); - - /* This is dead code, but go ahead and finish so that the - mode of the result comes out right. */ - *expr_p = dummy_object (type); - return GS_ALL_DONE; - } - - tag = build_int_cst (build_pointer_type (type), 0); - aptag = build_int_cst (TREE_TYPE (valist), 0); - - *expr_p = build_call_expr_internal_loc (loc, IFN_VA_ARG, type, 3, - valist, tag, aptag); - - /* Clear the tentatively set PROP_gimple_lva, to indicate that IFN_VA_ARG - needs to be expanded. */ - cfun->curr_properties &= ~PROP_gimple_lva; - - return GS_OK; -} - -/* Build a new GIMPLE_ASSIGN tuple and append it to the end of *SEQ_P. - - DST/SRC are the destination and source respectively. You can pass - ungimplified trees in DST or SRC, in which case they will be - converted to a gimple operand if necessary. - - This function returns the newly created GIMPLE_ASSIGN tuple. */ - -gimple * -gimplify_assign (tree dst, tree src, gimple_seq *seq_p) -{ - tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); - gimplify_and_add (t, seq_p); - ggc_free (t); - return gimple_seq_last_stmt (*seq_p); -} - -inline hashval_t -gimplify_hasher::hash (const elt_t *p) -{ - tree t = p->val; - return iterative_hash_expr (t, 0); -} - -inline bool -gimplify_hasher::equal (const elt_t *p1, const elt_t *p2) -{ - tree t1 = p1->val; - tree t2 = p2->val; - enum tree_code code = TREE_CODE (t1); - - if (TREE_CODE (t2) != code - || TREE_TYPE (t1) != TREE_TYPE (t2)) - return false; - - if (!operand_equal_p (t1, t2, 0)) - return false; - - /* Only allow them to compare equal if they also hash equal; otherwise - results are nondeterminate, and we fail bootstrap comparison. */ - gcc_checking_assert (hash (p1) == hash (p2)); - - return true; -} |