aboutsummaryrefslogtreecommitdiff
path: root/gcc/predict.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/predict.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/predict.c')
-rw-r--r--gcc/predict.c4566
1 files changed, 0 insertions, 4566 deletions
diff --git a/gcc/predict.c b/gcc/predict.c
deleted file mode 100644
index 36046ab..0000000
--- a/gcc/predict.c
+++ /dev/null
@@ -1,4566 +0,0 @@
-/* Branch prediction routines for the GNU compiler.
- Copyright (C) 2000-2022 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-/* References:
-
- [1] "Branch Prediction for Free"
- Ball and Larus; PLDI '93.
- [2] "Static Branch Frequency and Program Profile Analysis"
- Wu and Larus; MICRO-27.
- [3] "Corpus-based Static Branch Prediction"
- Calder, Grunwald, Lindsay, Martin, Mozer, and Zorn; PLDI '95. */
-
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "rtl.h"
-#include "tree.h"
-#include "gimple.h"
-#include "cfghooks.h"
-#include "tree-pass.h"
-#include "ssa.h"
-#include "memmodel.h"
-#include "emit-rtl.h"
-#include "cgraph.h"
-#include "coverage.h"
-#include "diagnostic-core.h"
-#include "gimple-predict.h"
-#include "fold-const.h"
-#include "calls.h"
-#include "cfganal.h"
-#include "profile.h"
-#include "sreal.h"
-#include "cfgloop.h"
-#include "gimple-iterator.h"
-#include "tree-cfg.h"
-#include "tree-ssa-loop-niter.h"
-#include "tree-ssa-loop.h"
-#include "tree-scalar-evolution.h"
-#include "ipa-utils.h"
-#include "gimple-pretty-print.h"
-#include "selftest.h"
-#include "cfgrtl.h"
-#include "stringpool.h"
-#include "attribs.h"
-
-/* Enum with reasons why a predictor is ignored. */
-
-enum predictor_reason
-{
- REASON_NONE,
- REASON_IGNORED,
- REASON_SINGLE_EDGE_DUPLICATE,
- REASON_EDGE_PAIR_DUPLICATE
-};
-
-/* String messages for the aforementioned enum. */
-
-static const char *reason_messages[] = {"", " (ignored)",
- " (single edge duplicate)", " (edge pair duplicate)"};
-
-
-static void combine_predictions_for_insn (rtx_insn *, basic_block);
-static void dump_prediction (FILE *, enum br_predictor, int, basic_block,
- enum predictor_reason, edge);
-static void predict_paths_leading_to (basic_block, enum br_predictor,
- enum prediction,
- class loop *in_loop = NULL);
-static void predict_paths_leading_to_edge (edge, enum br_predictor,
- enum prediction,
- class loop *in_loop = NULL);
-static bool can_predict_insn_p (const rtx_insn *);
-static HOST_WIDE_INT get_predictor_value (br_predictor, HOST_WIDE_INT);
-static void determine_unlikely_bbs ();
-
-/* Information we hold about each branch predictor.
- Filled using information from predict.def. */
-
-struct predictor_info
-{
- const char *const name; /* Name used in the debugging dumps. */
- const int hitrate; /* Expected hitrate used by
- predict_insn_def call. */
- const int flags;
-};
-
-/* Use given predictor without Dempster-Shaffer theory if it matches
- using first_match heuristics. */
-#define PRED_FLAG_FIRST_MATCH 1
-
-/* Recompute hitrate in percent to our representation. */
-
-#define HITRATE(VAL) ((int) ((VAL) * REG_BR_PROB_BASE + 50) / 100)
-
-#define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) {NAME, HITRATE, FLAGS},
-static const struct predictor_info predictor_info[]= {
-#include "predict.def"
-
- /* Upper bound on predictors. */
- {NULL, 0, 0}
-};
-#undef DEF_PREDICTOR
-
-static gcov_type min_count = -1;
-
-/* Determine the threshold for hot BB counts. */
-
-gcov_type
-get_hot_bb_threshold ()
-{
- if (min_count == -1)
- {
- const int hot_frac = param_hot_bb_count_fraction;
- const gcov_type min_hot_count
- = hot_frac
- ? profile_info->sum_max / hot_frac
- : (gcov_type)profile_count::max_count;
- set_hot_bb_threshold (min_hot_count);
- if (dump_file)
- fprintf (dump_file, "Setting hotness threshold to %" PRId64 ".\n",
- min_hot_count);
- }
- return min_count;
-}
-
-/* Set the threshold for hot BB counts. */
-
-void
-set_hot_bb_threshold (gcov_type min)
-{
- min_count = min;
-}
-
-/* Return TRUE if COUNT is considered to be hot in function FUN. */
-
-bool
-maybe_hot_count_p (struct function *fun, profile_count count)
-{
- if (!count.initialized_p ())
- return true;
- if (count.ipa () == profile_count::zero ())
- return false;
- if (!count.ipa_p ())
- {
- struct cgraph_node *node = cgraph_node::get (fun->decl);
- if (!profile_info || profile_status_for_fn (fun) != PROFILE_READ)
- {
- if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
- return false;
- if (node->frequency == NODE_FREQUENCY_HOT)
- return true;
- }
- if (profile_status_for_fn (fun) == PROFILE_ABSENT)
- return true;
- if (node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
- && count < (ENTRY_BLOCK_PTR_FOR_FN (fun)->count.apply_scale (2, 3)))
- return false;
- if (count.apply_scale (param_hot_bb_frequency_fraction, 1)
- < ENTRY_BLOCK_PTR_FOR_FN (fun)->count)
- return false;
- return true;
- }
- /* Code executed at most once is not hot. */
- if (count <= MAX (profile_info ? profile_info->runs : 1, 1))
- return false;
- return (count >= get_hot_bb_threshold ());
-}
-
-/* Return true if basic block BB of function FUN can be CPU intensive
- and should thus be optimized for maximum performance. */
-
-bool
-maybe_hot_bb_p (struct function *fun, const_basic_block bb)
-{
- gcc_checking_assert (fun);
- return maybe_hot_count_p (fun, bb->count);
-}
-
-/* Return true if edge E can be CPU intensive and should thus be optimized
- for maximum performance. */
-
-bool
-maybe_hot_edge_p (edge e)
-{
- return maybe_hot_count_p (cfun, e->count ());
-}
-
-/* Return true if COUNT is considered to be never executed in function FUN
- or if function FUN is considered so in the static profile. */
-
-static bool
-probably_never_executed (struct function *fun, profile_count count)
-{
- gcc_checking_assert (fun);
- if (count.ipa () == profile_count::zero ())
- return true;
- /* Do not trust adjusted counts. This will make us to drop int cold section
- code with low execution count as a result of inlining. These low counts
- are not safe even with read profile and may lead us to dropping
- code which actually gets executed into cold section of binary that is not
- desirable. */
- if (count.precise_p () && profile_status_for_fn (fun) == PROFILE_READ)
- {
- const int unlikely_frac = param_unlikely_bb_count_fraction;
- if (count.apply_scale (unlikely_frac, 1) >= profile_info->runs)
- return false;
- return true;
- }
- if ((!profile_info || profile_status_for_fn (fun) != PROFILE_READ)
- && (cgraph_node::get (fun->decl)->frequency
- == NODE_FREQUENCY_UNLIKELY_EXECUTED))
- return true;
- return false;
-}
-
-/* Return true if basic block BB of function FUN is probably never executed. */
-
-bool
-probably_never_executed_bb_p (struct function *fun, const_basic_block bb)
-{
- return probably_never_executed (fun, bb->count);
-}
-
-/* Return true if edge E is unlikely executed for obvious reasons. */
-
-static bool
-unlikely_executed_edge_p (edge e)
-{
- return (e->src->count == profile_count::zero ()
- || e->probability == profile_probability::never ())
- || (e->flags & (EDGE_EH | EDGE_FAKE));
-}
-
-/* Return true if edge E of function FUN is probably never executed. */
-
-bool
-probably_never_executed_edge_p (struct function *fun, edge e)
-{
- if (unlikely_executed_edge_p (e))
- return true;
- return probably_never_executed (fun, e->count ());
-}
-
-/* Return true if function FUN should always be optimized for size. */
-
-optimize_size_level
-optimize_function_for_size_p (struct function *fun)
-{
- if (!fun || !fun->decl)
- return optimize_size ? OPTIMIZE_SIZE_MAX : OPTIMIZE_SIZE_NO;
- cgraph_node *n = cgraph_node::get (fun->decl);
- if (n)
- return n->optimize_for_size_p ();
- return OPTIMIZE_SIZE_NO;
-}
-
-/* Return true if function FUN should always be optimized for speed. */
-
-bool
-optimize_function_for_speed_p (struct function *fun)
-{
- return !optimize_function_for_size_p (fun);
-}
-
-/* Return the optimization type that should be used for function FUN. */
-
-optimization_type
-function_optimization_type (struct function *fun)
-{
- return (optimize_function_for_speed_p (fun)
- ? OPTIMIZE_FOR_SPEED
- : OPTIMIZE_FOR_SIZE);
-}
-
-/* Return TRUE if basic block BB should be optimized for size. */
-
-optimize_size_level
-optimize_bb_for_size_p (const_basic_block bb)
-{
- enum optimize_size_level ret = optimize_function_for_size_p (cfun);
-
- if (bb && ret < OPTIMIZE_SIZE_MAX && bb->count == profile_count::zero ())
- ret = OPTIMIZE_SIZE_MAX;
- if (bb && ret < OPTIMIZE_SIZE_BALANCED && !maybe_hot_bb_p (cfun, bb))
- ret = OPTIMIZE_SIZE_BALANCED;
- return ret;
-}
-
-/* Return TRUE if basic block BB should be optimized for speed. */
-
-bool
-optimize_bb_for_speed_p (const_basic_block bb)
-{
- return !optimize_bb_for_size_p (bb);
-}
-
-/* Return the optimization type that should be used for basic block BB. */
-
-optimization_type
-bb_optimization_type (const_basic_block bb)
-{
- return (optimize_bb_for_speed_p (bb)
- ? OPTIMIZE_FOR_SPEED
- : OPTIMIZE_FOR_SIZE);
-}
-
-/* Return TRUE if edge E should be optimized for size. */
-
-optimize_size_level
-optimize_edge_for_size_p (edge e)
-{
- enum optimize_size_level ret = optimize_function_for_size_p (cfun);
-
- if (ret < OPTIMIZE_SIZE_MAX && unlikely_executed_edge_p (e))
- ret = OPTIMIZE_SIZE_MAX;
- if (ret < OPTIMIZE_SIZE_BALANCED && !maybe_hot_edge_p (e))
- ret = OPTIMIZE_SIZE_BALANCED;
- return ret;
-}
-
-/* Return TRUE if edge E should be optimized for speed. */
-
-bool
-optimize_edge_for_speed_p (edge e)
-{
- return !optimize_edge_for_size_p (e);
-}
-
-/* Return TRUE if the current function is optimized for size. */
-
-optimize_size_level
-optimize_insn_for_size_p (void)
-{
- enum optimize_size_level ret = optimize_function_for_size_p (cfun);
- if (ret < OPTIMIZE_SIZE_BALANCED && !crtl->maybe_hot_insn_p)
- ret = OPTIMIZE_SIZE_BALANCED;
- return ret;
-}
-
-/* Return TRUE if the current function is optimized for speed. */
-
-bool
-optimize_insn_for_speed_p (void)
-{
- return !optimize_insn_for_size_p ();
-}
-
-/* Return TRUE if LOOP should be optimized for size. */
-
-optimize_size_level
-optimize_loop_for_size_p (class loop *loop)
-{
- return optimize_bb_for_size_p (loop->header);
-}
-
-/* Return TRUE if LOOP should be optimized for speed. */
-
-bool
-optimize_loop_for_speed_p (class loop *loop)
-{
- return optimize_bb_for_speed_p (loop->header);
-}
-
-/* Return TRUE if nest rooted at LOOP should be optimized for speed. */
-
-bool
-optimize_loop_nest_for_speed_p (class loop *loop)
-{
- class loop *l = loop;
- if (optimize_loop_for_speed_p (loop))
- return true;
- l = loop->inner;
- while (l && l != loop)
- {
- if (optimize_loop_for_speed_p (l))
- return true;
- if (l->inner)
- l = l->inner;
- else if (l->next)
- l = l->next;
- else
- {
- while (l != loop && !l->next)
- l = loop_outer (l);
- if (l != loop)
- l = l->next;
- }
- }
- return false;
-}
-
-/* Return TRUE if nest rooted at LOOP should be optimized for size. */
-
-optimize_size_level
-optimize_loop_nest_for_size_p (class loop *loop)
-{
- enum optimize_size_level ret = optimize_loop_for_size_p (loop);
- class loop *l = loop;
-
- l = loop->inner;
- while (l && l != loop)
- {
- if (ret == OPTIMIZE_SIZE_NO)
- break;
- ret = MIN (optimize_loop_for_size_p (l), ret);
- if (l->inner)
- l = l->inner;
- else if (l->next)
- l = l->next;
- else
- {
- while (l != loop && !l->next)
- l = loop_outer (l);
- if (l != loop)
- l = l->next;
- }
- }
- return ret;
-}
-
-/* Return true if edge E is likely to be well predictable by branch
- predictor. */
-
-bool
-predictable_edge_p (edge e)
-{
- if (!e->probability.initialized_p ())
- return false;
- if ((e->probability.to_reg_br_prob_base ()
- <= param_predictable_branch_outcome * REG_BR_PROB_BASE / 100)
- || (REG_BR_PROB_BASE - e->probability.to_reg_br_prob_base ()
- <= param_predictable_branch_outcome * REG_BR_PROB_BASE / 100))
- return true;
- return false;
-}
-
-
-/* Set RTL expansion for BB profile. */
-
-void
-rtl_profile_for_bb (basic_block bb)
-{
- crtl->maybe_hot_insn_p = maybe_hot_bb_p (cfun, bb);
-}
-
-/* Set RTL expansion for edge profile. */
-
-void
-rtl_profile_for_edge (edge e)
-{
- crtl->maybe_hot_insn_p = maybe_hot_edge_p (e);
-}
-
-/* Set RTL expansion to default mode (i.e. when profile info is not known). */
-void
-default_rtl_profile (void)
-{
- crtl->maybe_hot_insn_p = true;
-}
-
-/* Return true if the one of outgoing edges is already predicted by
- PREDICTOR. */
-
-bool
-rtl_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
-{
- rtx note;
- if (!INSN_P (BB_END (bb)))
- return false;
- for (note = REG_NOTES (BB_END (bb)); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_BR_PRED
- && INTVAL (XEXP (XEXP (note, 0), 0)) == (int)predictor)
- return true;
- return false;
-}
-
-/* Structure representing predictions in tree level. */
-
-struct edge_prediction {
- struct edge_prediction *ep_next;
- edge ep_edge;
- enum br_predictor ep_predictor;
- int ep_probability;
-};
-
-/* This map contains for a basic block the list of predictions for the
- outgoing edges. */
-
-static hash_map<const_basic_block, edge_prediction *> *bb_predictions;
-
-/* Return true if the one of outgoing edges is already predicted by
- PREDICTOR. */
-
-bool
-gimple_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
-{
- struct edge_prediction *i;
- edge_prediction **preds = bb_predictions->get (bb);
-
- if (!preds)
- return false;
-
- for (i = *preds; i; i = i->ep_next)
- if (i->ep_predictor == predictor)
- return true;
- return false;
-}
-
-/* Return true if the one of outgoing edges is already predicted by
- PREDICTOR for edge E predicted as TAKEN. */
-
-bool
-edge_predicted_by_p (edge e, enum br_predictor predictor, bool taken)
-{
- struct edge_prediction *i;
- basic_block bb = e->src;
- edge_prediction **preds = bb_predictions->get (bb);
- if (!preds)
- return false;
-
- int probability = predictor_info[(int) predictor].hitrate;
-
- if (taken != TAKEN)
- probability = REG_BR_PROB_BASE - probability;
-
- for (i = *preds; i; i = i->ep_next)
- if (i->ep_predictor == predictor
- && i->ep_edge == e
- && i->ep_probability == probability)
- return true;
- return false;
-}
-
-/* Same predicate as above, working on edges. */
-bool
-edge_probability_reliable_p (const_edge e)
-{
- return e->probability.probably_reliable_p ();
-}
-
-/* Same predicate as edge_probability_reliable_p, working on notes. */
-bool
-br_prob_note_reliable_p (const_rtx note)
-{
- gcc_assert (REG_NOTE_KIND (note) == REG_BR_PROB);
- return profile_probability::from_reg_br_prob_note
- (XINT (note, 0)).probably_reliable_p ();
-}
-
-static void
-predict_insn (rtx_insn *insn, enum br_predictor predictor, int probability)
-{
- gcc_assert (any_condjump_p (insn));
- if (!flag_guess_branch_prob)
- return;
-
- add_reg_note (insn, REG_BR_PRED,
- gen_rtx_CONCAT (VOIDmode,
- GEN_INT ((int) predictor),
- GEN_INT ((int) probability)));
-}
-
-/* Predict insn by given predictor. */
-
-void
-predict_insn_def (rtx_insn *insn, enum br_predictor predictor,
- enum prediction taken)
-{
- int probability = predictor_info[(int) predictor].hitrate;
- gcc_assert (probability != PROB_UNINITIALIZED);
-
- if (taken != TAKEN)
- probability = REG_BR_PROB_BASE - probability;
-
- predict_insn (insn, predictor, probability);
-}
-
-/* Predict edge E with given probability if possible. */
-
-void
-rtl_predict_edge (edge e, enum br_predictor predictor, int probability)
-{
- rtx_insn *last_insn;
- last_insn = BB_END (e->src);
-
- /* We can store the branch prediction information only about
- conditional jumps. */
- if (!any_condjump_p (last_insn))
- return;
-
- /* We always store probability of branching. */
- if (e->flags & EDGE_FALLTHRU)
- probability = REG_BR_PROB_BASE - probability;
-
- predict_insn (last_insn, predictor, probability);
-}
-
-/* Predict edge E with the given PROBABILITY. */
-void
-gimple_predict_edge (edge e, enum br_predictor predictor, int probability)
-{
- if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
- && EDGE_COUNT (e->src->succs) > 1
- && flag_guess_branch_prob
- && optimize)
- {
- struct edge_prediction *i = XNEW (struct edge_prediction);
- edge_prediction *&preds = bb_predictions->get_or_insert (e->src);
-
- i->ep_next = preds;
- preds = i;
- i->ep_probability = probability;
- i->ep_predictor = predictor;
- i->ep_edge = e;
- }
-}
-
-/* Filter edge predictions PREDS by a function FILTER: if FILTER return false
- the prediction is removed.
- DATA are passed to the filter function. */
-
-static void
-filter_predictions (edge_prediction **preds,
- bool (*filter) (edge_prediction *, void *), void *data)
-{
- if (!bb_predictions)
- return;
-
- if (preds)
- {
- struct edge_prediction **prediction = preds;
- struct edge_prediction *next;
-
- while (*prediction)
- {
- if ((*filter) (*prediction, data))
- prediction = &((*prediction)->ep_next);
- else
- {
- next = (*prediction)->ep_next;
- free (*prediction);
- *prediction = next;
- }
- }
- }
-}
-
-/* Filter function predicate that returns true for a edge predicate P
- if its edge is equal to DATA. */
-
-static bool
-not_equal_edge_p (edge_prediction *p, void *data)
-{
- return p->ep_edge != (edge)data;
-}
-
-/* Remove all predictions on given basic block that are attached
- to edge E. */
-void
-remove_predictions_associated_with_edge (edge e)
-{
- if (!bb_predictions)
- return;
-
- edge_prediction **preds = bb_predictions->get (e->src);
- filter_predictions (preds, not_equal_edge_p, e);
-}
-
-/* Clears the list of predictions stored for BB. */
-
-static void
-clear_bb_predictions (basic_block bb)
-{
- edge_prediction **preds = bb_predictions->get (bb);
- struct edge_prediction *pred, *next;
-
- if (!preds)
- return;
-
- for (pred = *preds; pred; pred = next)
- {
- next = pred->ep_next;
- free (pred);
- }
- *preds = NULL;
-}
-
-/* Return true when we can store prediction on insn INSN.
- At the moment we represent predictions only on conditional
- jumps, not at computed jump or other complicated cases. */
-static bool
-can_predict_insn_p (const rtx_insn *insn)
-{
- return (JUMP_P (insn)
- && any_condjump_p (insn)
- && EDGE_COUNT (BLOCK_FOR_INSN (insn)->succs) >= 2);
-}
-
-/* Predict edge E by given predictor if possible. */
-
-void
-predict_edge_def (edge e, enum br_predictor predictor,
- enum prediction taken)
-{
- int probability = predictor_info[(int) predictor].hitrate;
-
- if (taken != TAKEN)
- probability = REG_BR_PROB_BASE - probability;
-
- predict_edge (e, predictor, probability);
-}
-
-/* Invert all branch predictions or probability notes in the INSN. This needs
- to be done each time we invert the condition used by the jump. */
-
-void
-invert_br_probabilities (rtx insn)
-{
- rtx note;
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_BR_PROB)
- XINT (note, 0) = profile_probability::from_reg_br_prob_note
- (XINT (note, 0)).invert ().to_reg_br_prob_note ();
- else if (REG_NOTE_KIND (note) == REG_BR_PRED)
- XEXP (XEXP (note, 0), 1)
- = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (XEXP (note, 0), 1)));
-}
-
-/* Dump information about the branch prediction to the output file. */
-
-static void
-dump_prediction (FILE *file, enum br_predictor predictor, int probability,
- basic_block bb, enum predictor_reason reason = REASON_NONE,
- edge ep_edge = NULL)
-{
- edge e = ep_edge;
- edge_iterator ei;
-
- if (!file)
- return;
-
- if (e == NULL)
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (! (e->flags & EDGE_FALLTHRU))
- break;
-
- char edge_info_str[128];
- if (ep_edge)
- sprintf (edge_info_str, " of edge %d->%d", ep_edge->src->index,
- ep_edge->dest->index);
- else
- edge_info_str[0] = '\0';
-
- fprintf (file, " %s heuristics%s%s: %.2f%%",
- predictor_info[predictor].name,
- edge_info_str, reason_messages[reason],
- probability * 100.0 / REG_BR_PROB_BASE);
-
- if (bb->count.initialized_p ())
- {
- fprintf (file, " exec ");
- bb->count.dump (file);
- if (e)
- {
- fprintf (file, " hit ");
- e->count ().dump (file);
- fprintf (file, " (%.1f%%)", e->count ().to_gcov_type() * 100.0
- / bb->count.to_gcov_type ());
- }
- }
-
- fprintf (file, "\n");
-
- /* Print output that be easily read by analyze_brprob.py script. We are
- interested only in counts that are read from GCDA files. */
- if (dump_file && (dump_flags & TDF_DETAILS)
- && bb->count.precise_p ()
- && reason == REASON_NONE)
- {
- fprintf (file, ";;heuristics;%s;%" PRId64 ";%" PRId64 ";%.1f;\n",
- predictor_info[predictor].name,
- bb->count.to_gcov_type (), e->count ().to_gcov_type (),
- probability * 100.0 / REG_BR_PROB_BASE);
- }
-}
-
-/* Return true if STMT is known to be unlikely executed. */
-
-static bool
-unlikely_executed_stmt_p (gimple *stmt)
-{
- if (!is_gimple_call (stmt))
- return false;
- /* NORETURN attribute alone is not strong enough: exit() may be quite
- likely executed once during program run. */
- if (gimple_call_fntype (stmt)
- && lookup_attribute ("cold",
- TYPE_ATTRIBUTES (gimple_call_fntype (stmt)))
- && !lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)))
- return true;
- tree decl = gimple_call_fndecl (stmt);
- if (!decl)
- return false;
- if (lookup_attribute ("cold", DECL_ATTRIBUTES (decl))
- && !lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)))
- return true;
-
- cgraph_node *n = cgraph_node::get (decl);
- if (!n)
- return false;
-
- availability avail;
- n = n->ultimate_alias_target (&avail);
- if (avail < AVAIL_AVAILABLE)
- return false;
- if (!n->analyzed
- || n->decl == current_function_decl)
- return false;
- return n->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED;
-}
-
-/* Return true if BB is unlikely executed. */
-
-static bool
-unlikely_executed_bb_p (basic_block bb)
-{
- if (bb->count == profile_count::zero ())
- return true;
- if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun) || bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
- return false;
- for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
- !gsi_end_p (gsi); gsi_next (&gsi))
- {
- if (unlikely_executed_stmt_p (gsi_stmt (gsi)))
- return true;
- if (stmt_can_terminate_bb_p (gsi_stmt (gsi)))
- return false;
- }
- return false;
-}
-
-/* We cannot predict the probabilities of outgoing edges of bb. Set them
- evenly and hope for the best. If UNLIKELY_EDGES is not null, distribute
- even probability for all edges not mentioned in the set. These edges
- are given PROB_VERY_UNLIKELY probability. Similarly for LIKELY_EDGES,
- if we have exactly one likely edge, make the other edges predicted
- as not probable. */
-
-static void
-set_even_probabilities (basic_block bb,
- hash_set<edge> *unlikely_edges = NULL,
- hash_set<edge_prediction *> *likely_edges = NULL)
-{
- unsigned nedges = 0, unlikely_count = 0;
- edge e = NULL;
- edge_iterator ei;
- profile_probability all = profile_probability::always ();
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->probability.initialized_p ())
- all -= e->probability;
- else if (!unlikely_executed_edge_p (e))
- {
- nedges++;
- if (unlikely_edges != NULL && unlikely_edges->contains (e))
- {
- all -= profile_probability::very_unlikely ();
- unlikely_count++;
- }
- }
-
- /* Make the distribution even if all edges are unlikely. */
- unsigned likely_count = likely_edges ? likely_edges->elements () : 0;
- if (unlikely_count == nedges)
- {
- unlikely_edges = NULL;
- unlikely_count = 0;
- }
-
- /* If we have one likely edge, then use its probability and distribute
- remaining probabilities as even. */
- if (likely_count == 1)
- {
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->probability.initialized_p ())
- ;
- else if (!unlikely_executed_edge_p (e))
- {
- edge_prediction *prediction = *likely_edges->begin ();
- int p = prediction->ep_probability;
- profile_probability prob
- = profile_probability::from_reg_br_prob_base (p);
-
- if (prediction->ep_edge == e)
- e->probability = prob;
- else if (unlikely_edges != NULL && unlikely_edges->contains (e))
- e->probability = profile_probability::very_unlikely ();
- else
- {
- profile_probability remainder = prob.invert ();
- remainder -= profile_probability::very_unlikely ()
- .apply_scale (unlikely_count, 1);
- int count = nedges - unlikely_count - 1;
- gcc_assert (count >= 0);
-
- e->probability = remainder.apply_scale (1, count);
- }
- }
- else
- e->probability = profile_probability::never ();
- }
- else
- {
- /* Make all unlikely edges unlikely and the rest will have even
- probability. */
- unsigned scale = nedges - unlikely_count;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->probability.initialized_p ())
- ;
- else if (!unlikely_executed_edge_p (e))
- {
- if (unlikely_edges != NULL && unlikely_edges->contains (e))
- e->probability = profile_probability::very_unlikely ();
- else
- e->probability = all.apply_scale (1, scale);
- }
- else
- e->probability = profile_probability::never ();
- }
-}
-
-/* Add REG_BR_PROB note to JUMP with PROB. */
-
-void
-add_reg_br_prob_note (rtx_insn *jump, profile_probability prob)
-{
- gcc_checking_assert (JUMP_P (jump) && !find_reg_note (jump, REG_BR_PROB, 0));
- add_int_reg_note (jump, REG_BR_PROB, prob.to_reg_br_prob_note ());
-}
-
-/* Combine all REG_BR_PRED notes into single probability and attach REG_BR_PROB
- note if not already present. Remove now useless REG_BR_PRED notes. */
-
-static void
-combine_predictions_for_insn (rtx_insn *insn, basic_block bb)
-{
- rtx prob_note;
- rtx *pnote;
- rtx note;
- int best_probability = PROB_EVEN;
- enum br_predictor best_predictor = END_PREDICTORS;
- int combined_probability = REG_BR_PROB_BASE / 2;
- int d;
- bool first_match = false;
- bool found = false;
-
- if (!can_predict_insn_p (insn))
- {
- set_even_probabilities (bb);
- return;
- }
-
- prob_note = find_reg_note (insn, REG_BR_PROB, 0);
- pnote = &REG_NOTES (insn);
- if (dump_file)
- fprintf (dump_file, "Predictions for insn %i bb %i\n", INSN_UID (insn),
- bb->index);
-
- /* We implement "first match" heuristics and use probability guessed
- by predictor with smallest index. */
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_BR_PRED)
- {
- enum br_predictor predictor = ((enum br_predictor)
- INTVAL (XEXP (XEXP (note, 0), 0)));
- int probability = INTVAL (XEXP (XEXP (note, 0), 1));
-
- found = true;
- if (best_predictor > predictor
- && predictor_info[predictor].flags & PRED_FLAG_FIRST_MATCH)
- best_probability = probability, best_predictor = predictor;
-
- d = (combined_probability * probability
- + (REG_BR_PROB_BASE - combined_probability)
- * (REG_BR_PROB_BASE - probability));
-
- /* Use FP math to avoid overflows of 32bit integers. */
- if (d == 0)
- /* If one probability is 0% and one 100%, avoid division by zero. */
- combined_probability = REG_BR_PROB_BASE / 2;
- else
- combined_probability = (((double) combined_probability) * probability
- * REG_BR_PROB_BASE / d + 0.5);
- }
-
- /* Decide which heuristic to use. In case we didn't match anything,
- use no_prediction heuristic, in case we did match, use either
- first match or Dempster-Shaffer theory depending on the flags. */
-
- if (best_predictor != END_PREDICTORS)
- first_match = true;
-
- if (!found)
- dump_prediction (dump_file, PRED_NO_PREDICTION,
- combined_probability, bb);
- else
- {
- if (!first_match)
- dump_prediction (dump_file, PRED_DS_THEORY, combined_probability,
- bb, !first_match ? REASON_NONE : REASON_IGNORED);
- else
- dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability,
- bb, first_match ? REASON_NONE : REASON_IGNORED);
- }
-
- if (first_match)
- combined_probability = best_probability;
- dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb);
-
- while (*pnote)
- {
- if (REG_NOTE_KIND (*pnote) == REG_BR_PRED)
- {
- enum br_predictor predictor = ((enum br_predictor)
- INTVAL (XEXP (XEXP (*pnote, 0), 0)));
- int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1));
-
- dump_prediction (dump_file, predictor, probability, bb,
- (!first_match || best_predictor == predictor)
- ? REASON_NONE : REASON_IGNORED);
- *pnote = XEXP (*pnote, 1);
- }
- else
- pnote = &XEXP (*pnote, 1);
- }
-
- if (!prob_note)
- {
- profile_probability p
- = profile_probability::from_reg_br_prob_base (combined_probability);
- add_reg_br_prob_note (insn, p);
-
- /* Save the prediction into CFG in case we are seeing non-degenerated
- conditional jump. */
- if (!single_succ_p (bb))
- {
- BRANCH_EDGE (bb)->probability = p;
- FALLTHRU_EDGE (bb)->probability
- = BRANCH_EDGE (bb)->probability.invert ();
- }
- }
- else if (!single_succ_p (bb))
- {
- profile_probability prob = profile_probability::from_reg_br_prob_note
- (XINT (prob_note, 0));
-
- BRANCH_EDGE (bb)->probability = prob;
- FALLTHRU_EDGE (bb)->probability = prob.invert ();
- }
- else
- single_succ_edge (bb)->probability = profile_probability::always ();
-}
-
-/* Edge prediction hash traits. */
-
-struct predictor_hash: pointer_hash <edge_prediction>
-{
-
- static inline hashval_t hash (const edge_prediction *);
- static inline bool equal (const edge_prediction *, const edge_prediction *);
-};
-
-/* Calculate hash value of an edge prediction P based on predictor and
- normalized probability. */
-
-inline hashval_t
-predictor_hash::hash (const edge_prediction *p)
-{
- inchash::hash hstate;
- hstate.add_int (p->ep_predictor);
-
- int prob = p->ep_probability;
- if (prob > REG_BR_PROB_BASE / 2)
- prob = REG_BR_PROB_BASE - prob;
-
- hstate.add_int (prob);
-
- return hstate.end ();
-}
-
-/* Return true whether edge predictions P1 and P2 use the same predictor and
- have equal (or opposed probability). */
-
-inline bool
-predictor_hash::equal (const edge_prediction *p1, const edge_prediction *p2)
-{
- return (p1->ep_predictor == p2->ep_predictor
- && (p1->ep_probability == p2->ep_probability
- || p1->ep_probability == REG_BR_PROB_BASE - p2->ep_probability));
-}
-
-struct predictor_hash_traits: predictor_hash,
- typed_noop_remove <edge_prediction *> {};
-
-/* Return true if edge prediction P is not in DATA hash set. */
-
-static bool
-not_removed_prediction_p (edge_prediction *p, void *data)
-{
- hash_set<edge_prediction *> *remove = (hash_set<edge_prediction *> *) data;
- return !remove->contains (p);
-}
-
-/* Prune predictions for a basic block BB. Currently we do following
- clean-up steps:
-
- 1) remove duplicate prediction that is guessed with the same probability
- (different than 1/2) to both edge
- 2) remove duplicates for a prediction that belongs with the same probability
- to a single edge
-
- */
-
-static void
-prune_predictions_for_bb (basic_block bb)
-{
- edge_prediction **preds = bb_predictions->get (bb);
-
- if (preds)
- {
- hash_table <predictor_hash_traits> s (13);
- hash_set <edge_prediction *> remove;
-
- /* Step 1: identify predictors that should be removed. */
- for (edge_prediction *pred = *preds; pred; pred = pred->ep_next)
- {
- edge_prediction *existing = s.find (pred);
- if (existing)
- {
- if (pred->ep_edge == existing->ep_edge
- && pred->ep_probability == existing->ep_probability)
- {
- /* Remove a duplicate predictor. */
- dump_prediction (dump_file, pred->ep_predictor,
- pred->ep_probability, bb,
- REASON_SINGLE_EDGE_DUPLICATE, pred->ep_edge);
-
- remove.add (pred);
- }
- else if (pred->ep_edge != existing->ep_edge
- && pred->ep_probability == existing->ep_probability
- && pred->ep_probability != REG_BR_PROB_BASE / 2)
- {
- /* Remove both predictors as they predict the same
- for both edges. */
- dump_prediction (dump_file, existing->ep_predictor,
- pred->ep_probability, bb,
- REASON_EDGE_PAIR_DUPLICATE,
- existing->ep_edge);
- dump_prediction (dump_file, pred->ep_predictor,
- pred->ep_probability, bb,
- REASON_EDGE_PAIR_DUPLICATE,
- pred->ep_edge);
-
- remove.add (existing);
- remove.add (pred);
- }
- }
-
- edge_prediction **slot2 = s.find_slot (pred, INSERT);
- *slot2 = pred;
- }
-
- /* Step 2: Remove predictors. */
- filter_predictions (preds, not_removed_prediction_p, &remove);
- }
-}
-
-/* Combine predictions into single probability and store them into CFG.
- Remove now useless prediction entries.
- If DRY_RUN is set, only produce dumps and do not modify profile. */
-
-static void
-combine_predictions_for_bb (basic_block bb, bool dry_run)
-{
- int best_probability = PROB_EVEN;
- enum br_predictor best_predictor = END_PREDICTORS;
- int combined_probability = REG_BR_PROB_BASE / 2;
- int d;
- bool first_match = false;
- bool found = false;
- struct edge_prediction *pred;
- int nedges = 0;
- edge e, first = NULL, second = NULL;
- edge_iterator ei;
- int nzero = 0;
- int nunknown = 0;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (!unlikely_executed_edge_p (e))
- {
- nedges ++;
- if (first && !second)
- second = e;
- if (!first)
- first = e;
- }
- else if (!e->probability.initialized_p ())
- e->probability = profile_probability::never ();
- if (!e->probability.initialized_p ())
- nunknown++;
- else if (e->probability == profile_probability::never ())
- nzero++;
- }
-
- /* When there is no successor or only one choice, prediction is easy.
-
- When we have a basic block with more than 2 successors, the situation
- is more complicated as DS theory cannot be used literally.
- More precisely, let's assume we predicted edge e1 with probability p1,
- thus: m1({b1}) = p1. As we're going to combine more than 2 edges, we
- need to find probability of e.g. m1({b2}), which we don't know.
- The only approximation is to equally distribute 1-p1 to all edges
- different from b1.
-
- According to numbers we've got from SPEC2006 benchark, there's only
- one interesting reliable predictor (noreturn call), which can be
- handled with a bit easier approach. */
- if (nedges != 2)
- {
- hash_set<edge> unlikely_edges (4);
- hash_set<edge_prediction *> likely_edges (4);
-
- /* Identify all edges that have a probability close to very unlikely.
- Doing the approach for very unlikely doesn't worth for doing as
- there's no such probability in SPEC2006 benchmark. */
- edge_prediction **preds = bb_predictions->get (bb);
- if (preds)
- for (pred = *preds; pred; pred = pred->ep_next)
- {
- if (pred->ep_probability <= PROB_VERY_UNLIKELY
- || pred->ep_predictor == PRED_COLD_LABEL)
- unlikely_edges.add (pred->ep_edge);
- else if (pred->ep_probability >= PROB_VERY_LIKELY
- || pred->ep_predictor == PRED_BUILTIN_EXPECT
- || pred->ep_predictor == PRED_HOT_LABEL)
- likely_edges.add (pred);
- }
-
- /* It can happen that an edge is both in likely_edges and unlikely_edges.
- Clear both sets in that situation. */
- for (hash_set<edge_prediction *>::iterator it = likely_edges.begin ();
- it != likely_edges.end (); ++it)
- if (unlikely_edges.contains ((*it)->ep_edge))
- {
- likely_edges.empty ();
- unlikely_edges.empty ();
- break;
- }
-
- if (!dry_run)
- set_even_probabilities (bb, &unlikely_edges, &likely_edges);
- clear_bb_predictions (bb);
- if (dump_file)
- {
- fprintf (dump_file, "Predictions for bb %i\n", bb->index);
- if (unlikely_edges.is_empty ())
- fprintf (dump_file,
- "%i edges in bb %i predicted to even probabilities\n",
- nedges, bb->index);
- else
- {
- fprintf (dump_file,
- "%i edges in bb %i predicted with some unlikely edges\n",
- nedges, bb->index);
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!unlikely_executed_edge_p (e))
- dump_prediction (dump_file, PRED_COMBINED,
- e->probability.to_reg_br_prob_base (), bb, REASON_NONE, e);
- }
- }
- return;
- }
-
- if (dump_file)
- fprintf (dump_file, "Predictions for bb %i\n", bb->index);
-
- prune_predictions_for_bb (bb);
-
- edge_prediction **preds = bb_predictions->get (bb);
-
- if (preds)
- {
- /* We implement "first match" heuristics and use probability guessed
- by predictor with smallest index. */
- for (pred = *preds; pred; pred = pred->ep_next)
- {
- enum br_predictor predictor = pred->ep_predictor;
- int probability = pred->ep_probability;
-
- if (pred->ep_edge != first)
- probability = REG_BR_PROB_BASE - probability;
-
- found = true;
- /* First match heuristics would be widly confused if we predicted
- both directions. */
- if (best_predictor > predictor
- && predictor_info[predictor].flags & PRED_FLAG_FIRST_MATCH)
- {
- struct edge_prediction *pred2;
- int prob = probability;
-
- for (pred2 = (struct edge_prediction *) *preds;
- pred2; pred2 = pred2->ep_next)
- if (pred2 != pred && pred2->ep_predictor == pred->ep_predictor)
- {
- int probability2 = pred2->ep_probability;
-
- if (pred2->ep_edge != first)
- probability2 = REG_BR_PROB_BASE - probability2;
-
- if ((probability < REG_BR_PROB_BASE / 2) !=
- (probability2 < REG_BR_PROB_BASE / 2))
- break;
-
- /* If the same predictor later gave better result, go for it! */
- if ((probability >= REG_BR_PROB_BASE / 2 && (probability2 > probability))
- || (probability <= REG_BR_PROB_BASE / 2 && (probability2 < probability)))
- prob = probability2;
- }
- if (!pred2)
- best_probability = prob, best_predictor = predictor;
- }
-
- d = (combined_probability * probability
- + (REG_BR_PROB_BASE - combined_probability)
- * (REG_BR_PROB_BASE - probability));
-
- /* Use FP math to avoid overflows of 32bit integers. */
- if (d == 0)
- /* If one probability is 0% and one 100%, avoid division by zero. */
- combined_probability = REG_BR_PROB_BASE / 2;
- else
- combined_probability = (((double) combined_probability)
- * probability
- * REG_BR_PROB_BASE / d + 0.5);
- }
- }
-
- /* Decide which heuristic to use. In case we didn't match anything,
- use no_prediction heuristic, in case we did match, use either
- first match or Dempster-Shaffer theory depending on the flags. */
-
- if (best_predictor != END_PREDICTORS)
- first_match = true;
-
- if (!found)
- dump_prediction (dump_file, PRED_NO_PREDICTION, combined_probability, bb);
- else
- {
- if (!first_match)
- dump_prediction (dump_file, PRED_DS_THEORY, combined_probability, bb,
- !first_match ? REASON_NONE : REASON_IGNORED);
- else
- dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability, bb,
- first_match ? REASON_NONE : REASON_IGNORED);
- }
-
- if (first_match)
- combined_probability = best_probability;
- dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb);
-
- if (preds)
- {
- for (pred = (struct edge_prediction *) *preds; pred; pred = pred->ep_next)
- {
- enum br_predictor predictor = pred->ep_predictor;
- int probability = pred->ep_probability;
-
- dump_prediction (dump_file, predictor, probability, bb,
- (!first_match || best_predictor == predictor)
- ? REASON_NONE : REASON_IGNORED, pred->ep_edge);
- }
- }
- clear_bb_predictions (bb);
-
-
- /* If we have only one successor which is unknown, we can compute missing
- probability. */
- if (nunknown == 1)
- {
- profile_probability prob = profile_probability::always ();
- edge missing = NULL;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->probability.initialized_p ())
- prob -= e->probability;
- else if (missing == NULL)
- missing = e;
- else
- gcc_unreachable ();
- missing->probability = prob;
- }
- /* If nothing is unknown, we have nothing to update. */
- else if (!nunknown && nzero != (int)EDGE_COUNT (bb->succs))
- ;
- else if (!dry_run)
- {
- first->probability
- = profile_probability::from_reg_br_prob_base (combined_probability);
- second->probability = first->probability.invert ();
- }
-}
-
-/* Check if T1 and T2 satisfy the IV_COMPARE condition.
- Return the SSA_NAME if the condition satisfies, NULL otherwise.
-
- T1 and T2 should be one of the following cases:
- 1. T1 is SSA_NAME, T2 is NULL
- 2. T1 is SSA_NAME, T2 is INTEGER_CST between [-4, 4]
- 3. T2 is SSA_NAME, T1 is INTEGER_CST between [-4, 4] */
-
-static tree
-strips_small_constant (tree t1, tree t2)
-{
- tree ret = NULL;
- int value = 0;
-
- if (!t1)
- return NULL;
- else if (TREE_CODE (t1) == SSA_NAME)
- ret = t1;
- else if (tree_fits_shwi_p (t1))
- value = tree_to_shwi (t1);
- else
- return NULL;
-
- if (!t2)
- return ret;
- else if (tree_fits_shwi_p (t2))
- value = tree_to_shwi (t2);
- else if (TREE_CODE (t2) == SSA_NAME)
- {
- if (ret)
- return NULL;
- else
- ret = t2;
- }
-
- if (value <= 4 && value >= -4)
- return ret;
- else
- return NULL;
-}
-
-/* Return the SSA_NAME in T or T's operands.
- Return NULL if SSA_NAME cannot be found. */
-
-static tree
-get_base_value (tree t)
-{
- if (TREE_CODE (t) == SSA_NAME)
- return t;
-
- if (!BINARY_CLASS_P (t))
- return NULL;
-
- switch (TREE_OPERAND_LENGTH (t))
- {
- case 1:
- return strips_small_constant (TREE_OPERAND (t, 0), NULL);
- case 2:
- return strips_small_constant (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
- default:
- return NULL;
- }
-}
-
-/* Check the compare STMT in LOOP. If it compares an induction
- variable to a loop invariant, return true, and save
- LOOP_INVARIANT, COMPARE_CODE and LOOP_STEP.
- Otherwise return false and set LOOP_INVAIANT to NULL. */
-
-static bool
-is_comparison_with_loop_invariant_p (gcond *stmt, class loop *loop,
- tree *loop_invariant,
- enum tree_code *compare_code,
- tree *loop_step,
- tree *loop_iv_base)
-{
- tree op0, op1, bound, base;
- affine_iv iv0, iv1;
- enum tree_code code;
- tree step;
-
- code = gimple_cond_code (stmt);
- *loop_invariant = NULL;
-
- switch (code)
- {
- case GT_EXPR:
- case GE_EXPR:
- case NE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- case EQ_EXPR:
- break;
-
- default:
- return false;
- }
-
- op0 = gimple_cond_lhs (stmt);
- op1 = gimple_cond_rhs (stmt);
-
- if ((TREE_CODE (op0) != SSA_NAME && TREE_CODE (op0) != INTEGER_CST)
- || (TREE_CODE (op1) != SSA_NAME && TREE_CODE (op1) != INTEGER_CST))
- return false;
- if (!simple_iv (loop, loop_containing_stmt (stmt), op0, &iv0, true))
- return false;
- if (!simple_iv (loop, loop_containing_stmt (stmt), op1, &iv1, true))
- return false;
- if (TREE_CODE (iv0.step) != INTEGER_CST
- || TREE_CODE (iv1.step) != INTEGER_CST)
- return false;
- if ((integer_zerop (iv0.step) && integer_zerop (iv1.step))
- || (!integer_zerop (iv0.step) && !integer_zerop (iv1.step)))
- return false;
-
- if (integer_zerop (iv0.step))
- {
- if (code != NE_EXPR && code != EQ_EXPR)
- code = invert_tree_comparison (code, false);
- bound = iv0.base;
- base = iv1.base;
- if (tree_fits_shwi_p (iv1.step))
- step = iv1.step;
- else
- return false;
- }
- else
- {
- bound = iv1.base;
- base = iv0.base;
- if (tree_fits_shwi_p (iv0.step))
- step = iv0.step;
- else
- return false;
- }
-
- if (TREE_CODE (bound) != INTEGER_CST)
- bound = get_base_value (bound);
- if (!bound)
- return false;
- if (TREE_CODE (base) != INTEGER_CST)
- base = get_base_value (base);
- if (!base)
- return false;
-
- *loop_invariant = bound;
- *compare_code = code;
- *loop_step = step;
- *loop_iv_base = base;
- return true;
-}
-
-/* Compare two SSA_NAMEs: returns TRUE if T1 and T2 are value coherent. */
-
-static bool
-expr_coherent_p (tree t1, tree t2)
-{
- gimple *stmt;
- tree ssa_name_1 = NULL;
- tree ssa_name_2 = NULL;
-
- gcc_assert (TREE_CODE (t1) == SSA_NAME || TREE_CODE (t1) == INTEGER_CST);
- gcc_assert (TREE_CODE (t2) == SSA_NAME || TREE_CODE (t2) == INTEGER_CST);
-
- if (t1 == t2)
- return true;
-
- if (TREE_CODE (t1) == INTEGER_CST && TREE_CODE (t2) == INTEGER_CST)
- return true;
- if (TREE_CODE (t1) == INTEGER_CST || TREE_CODE (t2) == INTEGER_CST)
- return false;
-
- /* Check to see if t1 is expressed/defined with t2. */
- stmt = SSA_NAME_DEF_STMT (t1);
- gcc_assert (stmt != NULL);
- if (is_gimple_assign (stmt))
- {
- ssa_name_1 = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_USE);
- if (ssa_name_1 && ssa_name_1 == t2)
- return true;
- }
-
- /* Check to see if t2 is expressed/defined with t1. */
- stmt = SSA_NAME_DEF_STMT (t2);
- gcc_assert (stmt != NULL);
- if (is_gimple_assign (stmt))
- {
- ssa_name_2 = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_USE);
- if (ssa_name_2 && ssa_name_2 == t1)
- return true;
- }
-
- /* Compare if t1 and t2's def_stmts are identical. */
- if (ssa_name_2 != NULL && ssa_name_1 == ssa_name_2)
- return true;
- else
- return false;
-}
-
-/* Return true if E is predicted by one of loop heuristics. */
-
-static bool
-predicted_by_loop_heuristics_p (basic_block bb)
-{
- struct edge_prediction *i;
- edge_prediction **preds = bb_predictions->get (bb);
-
- if (!preds)
- return false;
-
- for (i = *preds; i; i = i->ep_next)
- if (i->ep_predictor == PRED_LOOP_ITERATIONS_GUESSED
- || i->ep_predictor == PRED_LOOP_ITERATIONS_MAX
- || i->ep_predictor == PRED_LOOP_ITERATIONS
- || i->ep_predictor == PRED_LOOP_EXIT
- || i->ep_predictor == PRED_LOOP_EXIT_WITH_RECURSION
- || i->ep_predictor == PRED_LOOP_EXTRA_EXIT)
- return true;
- return false;
-}
-
-/* Predict branch probability of BB when BB contains a branch that compares
- an induction variable in LOOP with LOOP_IV_BASE_VAR to LOOP_BOUND_VAR. The
- loop exit is compared using LOOP_BOUND_CODE, with step of LOOP_BOUND_STEP.
-
- E.g.
- for (int i = 0; i < bound; i++) {
- if (i < bound - 2)
- computation_1();
- else
- computation_2();
- }
-
- In this loop, we will predict the branch inside the loop to be taken. */
-
-static void
-predict_iv_comparison (class loop *loop, basic_block bb,
- tree loop_bound_var,
- tree loop_iv_base_var,
- enum tree_code loop_bound_code,
- int loop_bound_step)
-{
- gimple *stmt;
- tree compare_var, compare_base;
- enum tree_code compare_code;
- tree compare_step_var;
- edge then_edge;
- edge_iterator ei;
-
- if (predicted_by_loop_heuristics_p (bb))
- return;
-
- stmt = last_stmt (bb);
- if (!stmt || gimple_code (stmt) != GIMPLE_COND)
- return;
- if (!is_comparison_with_loop_invariant_p (as_a <gcond *> (stmt),
- loop, &compare_var,
- &compare_code,
- &compare_step_var,
- &compare_base))
- return;
-
- /* Find the taken edge. */
- FOR_EACH_EDGE (then_edge, ei, bb->succs)
- if (then_edge->flags & EDGE_TRUE_VALUE)
- break;
-
- /* When comparing an IV to a loop invariant, NE is more likely to be
- taken while EQ is more likely to be not-taken. */
- if (compare_code == NE_EXPR)
- {
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- return;
- }
- else if (compare_code == EQ_EXPR)
- {
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, NOT_TAKEN);
- return;
- }
-
- if (!expr_coherent_p (loop_iv_base_var, compare_base))
- return;
-
- /* If loop bound, base and compare bound are all constants, we can
- calculate the probability directly. */
- if (tree_fits_shwi_p (loop_bound_var)
- && tree_fits_shwi_p (compare_var)
- && tree_fits_shwi_p (compare_base))
- {
- int probability;
- wi::overflow_type overflow;
- bool overall_overflow = false;
- widest_int compare_count, tem;
-
- /* (loop_bound - base) / compare_step */
- tem = wi::sub (wi::to_widest (loop_bound_var),
- wi::to_widest (compare_base), SIGNED, &overflow);
- overall_overflow |= overflow;
- widest_int loop_count = wi::div_trunc (tem,
- wi::to_widest (compare_step_var),
- SIGNED, &overflow);
- overall_overflow |= overflow;
-
- if (!wi::neg_p (wi::to_widest (compare_step_var))
- ^ (compare_code == LT_EXPR || compare_code == LE_EXPR))
- {
- /* (loop_bound - compare_bound) / compare_step */
- tem = wi::sub (wi::to_widest (loop_bound_var),
- wi::to_widest (compare_var), SIGNED, &overflow);
- overall_overflow |= overflow;
- compare_count = wi::div_trunc (tem, wi::to_widest (compare_step_var),
- SIGNED, &overflow);
- overall_overflow |= overflow;
- }
- else
- {
- /* (compare_bound - base) / compare_step */
- tem = wi::sub (wi::to_widest (compare_var),
- wi::to_widest (compare_base), SIGNED, &overflow);
- overall_overflow |= overflow;
- compare_count = wi::div_trunc (tem, wi::to_widest (compare_step_var),
- SIGNED, &overflow);
- overall_overflow |= overflow;
- }
- if (compare_code == LE_EXPR || compare_code == GE_EXPR)
- ++compare_count;
- if (loop_bound_code == LE_EXPR || loop_bound_code == GE_EXPR)
- ++loop_count;
- if (wi::neg_p (compare_count))
- compare_count = 0;
- if (wi::neg_p (loop_count))
- loop_count = 0;
- if (loop_count == 0)
- probability = 0;
- else if (wi::cmps (compare_count, loop_count) == 1)
- probability = REG_BR_PROB_BASE;
- else
- {
- tem = compare_count * REG_BR_PROB_BASE;
- tem = wi::udiv_trunc (tem, loop_count);
- probability = tem.to_uhwi ();
- }
-
- /* FIXME: The branch prediction seems broken. It has only 20% hitrate. */
- if (!overall_overflow)
- predict_edge (then_edge, PRED_LOOP_IV_COMPARE, probability);
-
- return;
- }
-
- if (expr_coherent_p (loop_bound_var, compare_var))
- {
- if ((loop_bound_code == LT_EXPR || loop_bound_code == LE_EXPR)
- && (compare_code == LT_EXPR || compare_code == LE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else if ((loop_bound_code == GT_EXPR || loop_bound_code == GE_EXPR)
- && (compare_code == GT_EXPR || compare_code == GE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else if (loop_bound_code == NE_EXPR)
- {
- /* If the loop backedge condition is "(i != bound)", we do
- the comparison based on the step of IV:
- * step < 0 : backedge condition is like (i > bound)
- * step > 0 : backedge condition is like (i < bound) */
- gcc_assert (loop_bound_step != 0);
- if (loop_bound_step > 0
- && (compare_code == LT_EXPR
- || compare_code == LE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else if (loop_bound_step < 0
- && (compare_code == GT_EXPR
- || compare_code == GE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, NOT_TAKEN);
- }
- else
- /* The branch is predicted not-taken if loop_bound_code is
- opposite with compare_code. */
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, NOT_TAKEN);
- }
- else if (expr_coherent_p (loop_iv_base_var, compare_var))
- {
- /* For cases like:
- for (i = s; i < h; i++)
- if (i > s + 2) ....
- The branch should be predicted taken. */
- if (loop_bound_step > 0
- && (compare_code == GT_EXPR || compare_code == GE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else if (loop_bound_step < 0
- && (compare_code == LT_EXPR || compare_code == LE_EXPR))
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, TAKEN);
- else
- predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, NOT_TAKEN);
- }
-}
-
-/* Predict for extra loop exits that will lead to EXIT_EDGE. The extra loop
- exits are resulted from short-circuit conditions that will generate an
- if_tmp. E.g.:
-
- if (foo() || global > 10)
- break;
-
- This will be translated into:
-
- BB3:
- loop header...
- BB4:
- if foo() goto BB6 else goto BB5
- BB5:
- if global > 10 goto BB6 else goto BB7
- BB6:
- goto BB7
- BB7:
- iftmp = (PHI 0(BB5), 1(BB6))
- if iftmp == 1 goto BB8 else goto BB3
- BB8:
- outside of the loop...
-
- The edge BB7->BB8 is loop exit because BB8 is outside of the loop.
- From the dataflow, we can infer that BB4->BB6 and BB5->BB6 are also loop
- exits. This function takes BB7->BB8 as input, and finds out the extra loop
- exits to predict them using PRED_LOOP_EXTRA_EXIT. */
-
-static void
-predict_extra_loop_exits (class loop *loop, edge exit_edge)
-{
- unsigned i;
- bool check_value_one;
- gimple *lhs_def_stmt;
- gphi *phi_stmt;
- tree cmp_rhs, cmp_lhs;
- gimple *last;
- gcond *cmp_stmt;
-
- last = last_stmt (exit_edge->src);
- if (!last)
- return;
- cmp_stmt = dyn_cast <gcond *> (last);
- if (!cmp_stmt)
- return;
-
- cmp_rhs = gimple_cond_rhs (cmp_stmt);
- cmp_lhs = gimple_cond_lhs (cmp_stmt);
- if (!TREE_CONSTANT (cmp_rhs)
- || !(integer_zerop (cmp_rhs) || integer_onep (cmp_rhs)))
- return;
- if (TREE_CODE (cmp_lhs) != SSA_NAME)
- return;
-
- /* If check_value_one is true, only the phi_args with value '1' will lead
- to loop exit. Otherwise, only the phi_args with value '0' will lead to
- loop exit. */
- check_value_one = (((integer_onep (cmp_rhs))
- ^ (gimple_cond_code (cmp_stmt) == EQ_EXPR))
- ^ ((exit_edge->flags & EDGE_TRUE_VALUE) != 0));
-
- lhs_def_stmt = SSA_NAME_DEF_STMT (cmp_lhs);
- if (!lhs_def_stmt)
- return;
-
- phi_stmt = dyn_cast <gphi *> (lhs_def_stmt);
- if (!phi_stmt)
- return;
-
- for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
- {
- edge e1;
- edge_iterator ei;
- tree val = gimple_phi_arg_def (phi_stmt, i);
- edge e = gimple_phi_arg_edge (phi_stmt, i);
-
- if (!TREE_CONSTANT (val) || !(integer_zerop (val) || integer_onep (val)))
- continue;
- if ((check_value_one ^ integer_onep (val)) == 1)
- continue;
- if (EDGE_COUNT (e->src->succs) != 1)
- {
- predict_paths_leading_to_edge (e, PRED_LOOP_EXTRA_EXIT, NOT_TAKEN,
- loop);
- continue;
- }
-
- FOR_EACH_EDGE (e1, ei, e->src->preds)
- predict_paths_leading_to_edge (e1, PRED_LOOP_EXTRA_EXIT, NOT_TAKEN,
- loop);
- }
-}
-
-
-/* Predict edge probabilities by exploiting loop structure. */
-
-static void
-predict_loops (void)
-{
- basic_block bb;
- hash_set <class loop *> with_recursion(10);
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- gimple_stmt_iterator gsi;
- tree decl;
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (is_gimple_call (gsi_stmt (gsi))
- && (decl = gimple_call_fndecl (gsi_stmt (gsi))) != NULL
- && recursive_call_p (current_function_decl, decl))
- {
- class loop *loop = bb->loop_father;
- while (loop && !with_recursion.add (loop))
- loop = loop_outer (loop);
- }
- }
-
- /* Try to predict out blocks in a loop that are not part of a
- natural loop. */
- for (auto loop : loops_list (cfun, LI_FROM_INNERMOST))
- {
- basic_block bb, *bbs;
- unsigned j, n_exits = 0;
- class tree_niter_desc niter_desc;
- edge ex;
- class nb_iter_bound *nb_iter;
- enum tree_code loop_bound_code = ERROR_MARK;
- tree loop_bound_step = NULL;
- tree loop_bound_var = NULL;
- tree loop_iv_base = NULL;
- gcond *stmt = NULL;
- bool recursion = with_recursion.contains (loop);
-
- auto_vec<edge> exits = get_loop_exit_edges (loop);
- FOR_EACH_VEC_ELT (exits, j, ex)
- if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
- n_exits ++;
- if (!n_exits)
- continue;
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Predicting loop %i%s with %i exits.\n",
- loop->num, recursion ? " (with recursion)":"", n_exits);
- if (dump_file && (dump_flags & TDF_DETAILS)
- && max_loop_iterations_int (loop) >= 0)
- {
- fprintf (dump_file,
- "Loop %d iterates at most %i times.\n", loop->num,
- (int)max_loop_iterations_int (loop));
- }
- if (dump_file && (dump_flags & TDF_DETAILS)
- && likely_max_loop_iterations_int (loop) >= 0)
- {
- fprintf (dump_file, "Loop %d likely iterates at most %i times.\n",
- loop->num, (int)likely_max_loop_iterations_int (loop));
- }
-
- FOR_EACH_VEC_ELT (exits, j, ex)
- {
- tree niter = NULL;
- HOST_WIDE_INT nitercst;
- int max = param_max_predicted_iterations;
- int probability;
- enum br_predictor predictor;
- widest_int nit;
-
- if (unlikely_executed_edge_p (ex)
- || (ex->flags & EDGE_ABNORMAL_CALL))
- continue;
- /* Loop heuristics do not expect exit conditional to be inside
- inner loop. We predict from innermost to outermost loop. */
- if (predicted_by_loop_heuristics_p (ex->src))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Skipping exit %i->%i because "
- "it is already predicted.\n",
- ex->src->index, ex->dest->index);
- continue;
- }
- predict_extra_loop_exits (loop, ex);
-
- if (number_of_iterations_exit (loop, ex, &niter_desc, false, false))
- niter = niter_desc.niter;
- if (!niter || TREE_CODE (niter_desc.niter) != INTEGER_CST)
- niter = loop_niter_by_eval (loop, ex);
- if (dump_file && (dump_flags & TDF_DETAILS)
- && TREE_CODE (niter) == INTEGER_CST)
- {
- fprintf (dump_file, "Exit %i->%i %d iterates ",
- ex->src->index, ex->dest->index,
- loop->num);
- print_generic_expr (dump_file, niter, TDF_SLIM);
- fprintf (dump_file, " times.\n");
- }
-
- if (TREE_CODE (niter) == INTEGER_CST)
- {
- if (tree_fits_uhwi_p (niter)
- && max
- && compare_tree_int (niter, max - 1) == -1)
- nitercst = tree_to_uhwi (niter) + 1;
- else
- nitercst = max;
- predictor = PRED_LOOP_ITERATIONS;
- }
- /* If we have just one exit and we can derive some information about
- the number of iterations of the loop from the statements inside
- the loop, use it to predict this exit. */
- else if (n_exits == 1
- && estimated_stmt_executions (loop, &nit))
- {
- if (wi::gtu_p (nit, max))
- nitercst = max;
- else
- nitercst = nit.to_shwi ();
- predictor = PRED_LOOP_ITERATIONS_GUESSED;
- }
- /* If we have likely upper bound, trust it for very small iteration
- counts. Such loops would otherwise get mispredicted by standard
- LOOP_EXIT heuristics. */
- else if (n_exits == 1
- && likely_max_stmt_executions (loop, &nit)
- && wi::ltu_p (nit,
- RDIV (REG_BR_PROB_BASE,
- REG_BR_PROB_BASE
- - predictor_info
- [recursion
- ? PRED_LOOP_EXIT_WITH_RECURSION
- : PRED_LOOP_EXIT].hitrate)))
- {
- nitercst = nit.to_shwi ();
- predictor = PRED_LOOP_ITERATIONS_MAX;
- }
- else
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Nothing known about exit %i->%i.\n",
- ex->src->index, ex->dest->index);
- continue;
- }
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Recording prediction to %i iterations by %s.\n",
- (int)nitercst, predictor_info[predictor].name);
- /* If the prediction for number of iterations is zero, do not
- predict the exit edges. */
- if (nitercst == 0)
- continue;
-
- probability = RDIV (REG_BR_PROB_BASE, nitercst);
- predict_edge (ex, predictor, probability);
- }
-
- /* Find information about loop bound variables. */
- for (nb_iter = loop->bounds; nb_iter;
- nb_iter = nb_iter->next)
- if (nb_iter->stmt
- && gimple_code (nb_iter->stmt) == GIMPLE_COND)
- {
- stmt = as_a <gcond *> (nb_iter->stmt);
- break;
- }
- if (!stmt && last_stmt (loop->header)
- && gimple_code (last_stmt (loop->header)) == GIMPLE_COND)
- stmt = as_a <gcond *> (last_stmt (loop->header));
- if (stmt)
- is_comparison_with_loop_invariant_p (stmt, loop,
- &loop_bound_var,
- &loop_bound_code,
- &loop_bound_step,
- &loop_iv_base);
-
- bbs = get_loop_body (loop);
-
- for (j = 0; j < loop->num_nodes; j++)
- {
- edge e;
- edge_iterator ei;
-
- bb = bbs[j];
-
- /* Bypass loop heuristics on continue statement. These
- statements construct loops via "non-loop" constructs
- in the source language and are better to be handled
- separately. */
- if (predicted_by_p (bb, PRED_CONTINUE))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "BB %i predicted by continue.\n",
- bb->index);
- continue;
- }
-
- /* If we already used more reliable loop exit predictors, do not
- bother with PRED_LOOP_EXIT. */
- if (!predicted_by_loop_heuristics_p (bb))
- {
- /* For loop with many exits we don't want to predict all exits
- with the pretty large probability, because if all exits are
- considered in row, the loop would be predicted to iterate
- almost never. The code to divide probability by number of
- exits is very rough. It should compute the number of exits
- taken in each patch through function (not the overall number
- of exits that might be a lot higher for loops with wide switch
- statements in them) and compute n-th square root.
-
- We limit the minimal probability by 2% to avoid
- EDGE_PROBABILITY_RELIABLE from trusting the branch prediction
- as this was causing regression in perl benchmark containing such
- a wide loop. */
-
- int probability = ((REG_BR_PROB_BASE
- - predictor_info
- [recursion
- ? PRED_LOOP_EXIT_WITH_RECURSION
- : PRED_LOOP_EXIT].hitrate)
- / n_exits);
- if (probability < HITRATE (2))
- probability = HITRATE (2);
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest->index < NUM_FIXED_BLOCKS
- || !flow_bb_inside_loop_p (loop, e->dest))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file,
- "Predicting exit %i->%i with prob %i.\n",
- e->src->index, e->dest->index, probability);
- predict_edge (e,
- recursion ? PRED_LOOP_EXIT_WITH_RECURSION
- : PRED_LOOP_EXIT, probability);
- }
- }
- if (loop_bound_var)
- predict_iv_comparison (loop, bb, loop_bound_var, loop_iv_base,
- loop_bound_code,
- tree_to_shwi (loop_bound_step));
- }
-
- /* In the following code
- for (loop1)
- if (cond)
- for (loop2)
- body;
- guess that cond is unlikely. */
- if (loop_outer (loop)->num)
- {
- basic_block bb = NULL;
- edge preheader_edge = loop_preheader_edge (loop);
-
- if (single_pred_p (preheader_edge->src)
- && single_succ_p (preheader_edge->src))
- preheader_edge = single_pred_edge (preheader_edge->src);
-
- gimple *stmt = last_stmt (preheader_edge->src);
- /* Pattern match fortran loop preheader:
- _16 = BUILTIN_EXPECT (_15, 1, PRED_FORTRAN_LOOP_PREHEADER);
- _17 = (logical(kind=4)) _16;
- if (_17 != 0)
- goto <bb 11>;
- else
- goto <bb 13>;
-
- Loop guard branch prediction says nothing about duplicated loop
- headers produced by fortran frontend and in this case we want
- to predict paths leading to this preheader. */
-
- if (stmt
- && gimple_code (stmt) == GIMPLE_COND
- && gimple_cond_code (stmt) == NE_EXPR
- && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME
- && integer_zerop (gimple_cond_rhs (stmt)))
- {
- gimple *call_stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt));
- if (gimple_code (call_stmt) == GIMPLE_ASSIGN
- && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (call_stmt))
- && TREE_CODE (gimple_assign_rhs1 (call_stmt)) == SSA_NAME)
- call_stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (call_stmt));
- if (gimple_call_internal_p (call_stmt, IFN_BUILTIN_EXPECT)
- && TREE_CODE (gimple_call_arg (call_stmt, 2)) == INTEGER_CST
- && tree_fits_uhwi_p (gimple_call_arg (call_stmt, 2))
- && tree_to_uhwi (gimple_call_arg (call_stmt, 2))
- == PRED_FORTRAN_LOOP_PREHEADER)
- bb = preheader_edge->src;
- }
- if (!bb)
- {
- if (!dominated_by_p (CDI_DOMINATORS,
- loop_outer (loop)->latch, loop->header))
- predict_paths_leading_to_edge (loop_preheader_edge (loop),
- recursion
- ? PRED_LOOP_GUARD_WITH_RECURSION
- : PRED_LOOP_GUARD,
- NOT_TAKEN,
- loop_outer (loop));
- }
- else
- {
- if (!dominated_by_p (CDI_DOMINATORS,
- loop_outer (loop)->latch, bb))
- predict_paths_leading_to (bb,
- recursion
- ? PRED_LOOP_GUARD_WITH_RECURSION
- : PRED_LOOP_GUARD,
- NOT_TAKEN,
- loop_outer (loop));
- }
- }
-
- /* Free basic blocks from get_loop_body. */
- free (bbs);
- }
-}
-
-/* Attempt to predict probabilities of BB outgoing edges using local
- properties. */
-static void
-bb_estimate_probability_locally (basic_block bb)
-{
- rtx_insn *last_insn = BB_END (bb);
- rtx cond;
-
- if (! can_predict_insn_p (last_insn))
- return;
- cond = get_condition (last_insn, NULL, false, false);
- if (! cond)
- return;
-
- /* Try "pointer heuristic."
- A comparison ptr == 0 is predicted as false.
- Similarly, a comparison ptr1 == ptr2 is predicted as false. */
- if (COMPARISON_P (cond)
- && ((REG_P (XEXP (cond, 0)) && REG_POINTER (XEXP (cond, 0)))
- || (REG_P (XEXP (cond, 1)) && REG_POINTER (XEXP (cond, 1)))))
- {
- if (GET_CODE (cond) == EQ)
- predict_insn_def (last_insn, PRED_POINTER, NOT_TAKEN);
- else if (GET_CODE (cond) == NE)
- predict_insn_def (last_insn, PRED_POINTER, TAKEN);
- }
- else
-
- /* Try "opcode heuristic."
- EQ tests are usually false and NE tests are usually true. Also,
- most quantities are positive, so we can make the appropriate guesses
- about signed comparisons against zero. */
- switch (GET_CODE (cond))
- {
- case CONST_INT:
- /* Unconditional branch. */
- predict_insn_def (last_insn, PRED_UNCONDITIONAL,
- cond == const0_rtx ? NOT_TAKEN : TAKEN);
- break;
-
- case EQ:
- case UNEQ:
- /* Floating point comparisons appears to behave in a very
- unpredictable way because of special role of = tests in
- FP code. */
- if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
- ;
- /* Comparisons with 0 are often used for booleans and there is
- nothing useful to predict about them. */
- else if (XEXP (cond, 1) == const0_rtx
- || XEXP (cond, 0) == const0_rtx)
- ;
- else
- predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, NOT_TAKEN);
- break;
-
- case NE:
- case LTGT:
- /* Floating point comparisons appears to behave in a very
- unpredictable way because of special role of = tests in
- FP code. */
- if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
- ;
- /* Comparisons with 0 are often used for booleans and there is
- nothing useful to predict about them. */
- else if (XEXP (cond, 1) == const0_rtx
- || XEXP (cond, 0) == const0_rtx)
- ;
- else
- predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, TAKEN);
- break;
-
- case ORDERED:
- predict_insn_def (last_insn, PRED_FPOPCODE, TAKEN);
- break;
-
- case UNORDERED:
- predict_insn_def (last_insn, PRED_FPOPCODE, NOT_TAKEN);
- break;
-
- case LE:
- case LT:
- if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
- || XEXP (cond, 1) == constm1_rtx)
- predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, NOT_TAKEN);
- break;
-
- case GE:
- case GT:
- if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
- || XEXP (cond, 1) == constm1_rtx)
- predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, TAKEN);
- break;
-
- default:
- break;
- }
-}
-
-/* Set edge->probability for each successor edge of BB. */
-void
-guess_outgoing_edge_probabilities (basic_block bb)
-{
- bb_estimate_probability_locally (bb);
- combine_predictions_for_insn (BB_END (bb), bb);
-}
-
-static tree expr_expected_value (tree, bitmap, enum br_predictor *predictor,
- HOST_WIDE_INT *probability);
-
-/* Helper function for expr_expected_value. */
-
-static tree
-expr_expected_value_1 (tree type, tree op0, enum tree_code code,
- tree op1, bitmap visited, enum br_predictor *predictor,
- HOST_WIDE_INT *probability)
-{
- gimple *def;
-
- /* Reset returned probability value. */
- *probability = -1;
- *predictor = PRED_UNCONDITIONAL;
-
- if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS)
- {
- if (TREE_CONSTANT (op0))
- return op0;
-
- if (code == IMAGPART_EXPR)
- {
- if (TREE_CODE (TREE_OPERAND (op0, 0)) == SSA_NAME)
- {
- def = SSA_NAME_DEF_STMT (TREE_OPERAND (op0, 0));
- if (is_gimple_call (def)
- && gimple_call_internal_p (def)
- && (gimple_call_internal_fn (def)
- == IFN_ATOMIC_COMPARE_EXCHANGE))
- {
- /* Assume that any given atomic operation has low contention,
- and thus the compare-and-swap operation succeeds. */
- *predictor = PRED_COMPARE_AND_SWAP;
- return build_one_cst (TREE_TYPE (op0));
- }
- }
- }
-
- if (code != SSA_NAME)
- return NULL_TREE;
-
- def = SSA_NAME_DEF_STMT (op0);
-
- /* If we were already here, break the infinite cycle. */
- if (!bitmap_set_bit (visited, SSA_NAME_VERSION (op0)))
- return NULL;
-
- if (gimple_code (def) == GIMPLE_PHI)
- {
- /* All the arguments of the PHI node must have the same constant
- length. */
- int i, n = gimple_phi_num_args (def);
- tree val = NULL, new_val;
-
- for (i = 0; i < n; i++)
- {
- tree arg = PHI_ARG_DEF (def, i);
- enum br_predictor predictor2;
-
- /* If this PHI has itself as an argument, we cannot
- determine the string length of this argument. However,
- if we can find an expected constant value for the other
- PHI args then we can still be sure that this is
- likely a constant. So be optimistic and just
- continue with the next argument. */
- if (arg == PHI_RESULT (def))
- continue;
-
- HOST_WIDE_INT probability2;
- new_val = expr_expected_value (arg, visited, &predictor2,
- &probability2);
-
- /* It is difficult to combine value predictors. Simply assume
- that later predictor is weaker and take its prediction. */
- if (*predictor < predictor2)
- {
- *predictor = predictor2;
- *probability = probability2;
- }
- if (!new_val)
- return NULL;
- if (!val)
- val = new_val;
- else if (!operand_equal_p (val, new_val, false))
- return NULL;
- }
- return val;
- }
- if (is_gimple_assign (def))
- {
- if (gimple_assign_lhs (def) != op0)
- return NULL;
-
- return expr_expected_value_1 (TREE_TYPE (gimple_assign_lhs (def)),
- gimple_assign_rhs1 (def),
- gimple_assign_rhs_code (def),
- gimple_assign_rhs2 (def),
- visited, predictor, probability);
- }
-
- if (is_gimple_call (def))
- {
- tree decl = gimple_call_fndecl (def);
- if (!decl)
- {
- if (gimple_call_internal_p (def)
- && gimple_call_internal_fn (def) == IFN_BUILTIN_EXPECT)
- {
- gcc_assert (gimple_call_num_args (def) == 3);
- tree val = gimple_call_arg (def, 0);
- if (TREE_CONSTANT (val))
- return val;
- tree val2 = gimple_call_arg (def, 2);
- gcc_assert (TREE_CODE (val2) == INTEGER_CST
- && tree_fits_uhwi_p (val2)
- && tree_to_uhwi (val2) < END_PREDICTORS);
- *predictor = (enum br_predictor) tree_to_uhwi (val2);
- if (*predictor == PRED_BUILTIN_EXPECT)
- *probability
- = HITRATE (param_builtin_expect_probability);
- return gimple_call_arg (def, 1);
- }
- return NULL;
- }
-
- if (DECL_IS_MALLOC (decl) || DECL_IS_OPERATOR_NEW_P (decl))
- {
- if (predictor)
- *predictor = PRED_MALLOC_NONNULL;
- return boolean_true_node;
- }
-
- if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (decl))
- {
- case BUILT_IN_EXPECT:
- {
- tree val;
- if (gimple_call_num_args (def) != 2)
- return NULL;
- val = gimple_call_arg (def, 0);
- if (TREE_CONSTANT (val))
- return val;
- *predictor = PRED_BUILTIN_EXPECT;
- *probability
- = HITRATE (param_builtin_expect_probability);
- return gimple_call_arg (def, 1);
- }
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- {
- tree val;
- if (gimple_call_num_args (def) != 3)
- return NULL;
- val = gimple_call_arg (def, 0);
- if (TREE_CONSTANT (val))
- return val;
- /* Compute final probability as:
- probability * REG_BR_PROB_BASE. */
- tree prob = gimple_call_arg (def, 2);
- tree t = TREE_TYPE (prob);
- tree base = build_int_cst (integer_type_node,
- REG_BR_PROB_BASE);
- base = build_real_from_int_cst (t, base);
- tree r = fold_build2_initializer_loc (UNKNOWN_LOCATION,
- MULT_EXPR, t, prob, base);
- if (TREE_CODE (r) != REAL_CST)
- {
- error_at (gimple_location (def),
- "probability %qE must be "
- "constant floating-point expression", prob);
- return NULL;
- }
- HOST_WIDE_INT probi
- = real_to_integer (TREE_REAL_CST_PTR (r));
- if (probi >= 0 && probi <= REG_BR_PROB_BASE)
- {
- *predictor = PRED_BUILTIN_EXPECT_WITH_PROBABILITY;
- *probability = probi;
- }
- else
- error_at (gimple_location (def),
- "probability %qE is outside "
- "the range [0.0, 1.0]", prob);
-
- return gimple_call_arg (def, 1);
- }
-
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
- /* Assume that any given atomic operation has low contention,
- and thus the compare-and-swap operation succeeds. */
- *predictor = PRED_COMPARE_AND_SWAP;
- return boolean_true_node;
- case BUILT_IN_REALLOC:
- if (predictor)
- *predictor = PRED_MALLOC_NONNULL;
- return boolean_true_node;
- default:
- break;
- }
- }
-
- return NULL;
- }
-
- if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS)
- {
- tree res;
- enum br_predictor predictor2;
- HOST_WIDE_INT probability2;
- op0 = expr_expected_value (op0, visited, predictor, probability);
- if (!op0)
- return NULL;
- op1 = expr_expected_value (op1, visited, &predictor2, &probability2);
- if (!op1)
- return NULL;
- res = fold_build2 (code, type, op0, op1);
- if (TREE_CODE (res) == INTEGER_CST
- && TREE_CODE (op0) == INTEGER_CST
- && TREE_CODE (op1) == INTEGER_CST)
- {
- /* Combine binary predictions. */
- if (*probability != -1 || probability2 != -1)
- {
- HOST_WIDE_INT p1 = get_predictor_value (*predictor, *probability);
- HOST_WIDE_INT p2 = get_predictor_value (predictor2, probability2);
- *probability = RDIV (p1 * p2, REG_BR_PROB_BASE);
- }
-
- if (*predictor < predictor2)
- *predictor = predictor2;
-
- return res;
- }
- return NULL;
- }
- if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
- {
- tree res;
- op0 = expr_expected_value (op0, visited, predictor, probability);
- if (!op0)
- return NULL;
- res = fold_build1 (code, type, op0);
- if (TREE_CONSTANT (res))
- return res;
- return NULL;
- }
- return NULL;
-}
-
-/* Return constant EXPR will likely have at execution time, NULL if unknown.
- The function is used by builtin_expect branch predictor so the evidence
- must come from this construct and additional possible constant folding.
-
- We may want to implement more involved value guess (such as value range
- propagation based prediction), but such tricks shall go to new
- implementation. */
-
-static tree
-expr_expected_value (tree expr, bitmap visited,
- enum br_predictor *predictor,
- HOST_WIDE_INT *probability)
-{
- enum tree_code code;
- tree op0, op1;
-
- if (TREE_CONSTANT (expr))
- {
- *predictor = PRED_UNCONDITIONAL;
- *probability = -1;
- return expr;
- }
-
- extract_ops_from_tree (expr, &code, &op0, &op1);
- return expr_expected_value_1 (TREE_TYPE (expr),
- op0, code, op1, visited, predictor,
- probability);
-}
-
-
-/* Return probability of a PREDICTOR. If the predictor has variable
- probability return passed PROBABILITY. */
-
-static HOST_WIDE_INT
-get_predictor_value (br_predictor predictor, HOST_WIDE_INT probability)
-{
- switch (predictor)
- {
- case PRED_BUILTIN_EXPECT:
- case PRED_BUILTIN_EXPECT_WITH_PROBABILITY:
- gcc_assert (probability != -1);
- return probability;
- default:
- gcc_assert (probability == -1);
- return predictor_info[(int) predictor].hitrate;
- }
-}
-
-/* Predict using opcode of the last statement in basic block. */
-static void
-tree_predict_by_opcode (basic_block bb)
-{
- gimple *stmt = last_stmt (bb);
- edge then_edge;
- tree op0, op1;
- tree type;
- tree val;
- enum tree_code cmp;
- edge_iterator ei;
- enum br_predictor predictor;
- HOST_WIDE_INT probability;
-
- if (!stmt)
- return;
-
- if (gswitch *sw = dyn_cast <gswitch *> (stmt))
- {
- tree index = gimple_switch_index (sw);
- tree val = expr_expected_value (index, auto_bitmap (),
- &predictor, &probability);
- if (val && TREE_CODE (val) == INTEGER_CST)
- {
- edge e = find_taken_edge_switch_expr (sw, val);
- if (predictor == PRED_BUILTIN_EXPECT)
- {
- int percent = param_builtin_expect_probability;
- gcc_assert (percent >= 0 && percent <= 100);
- predict_edge (e, PRED_BUILTIN_EXPECT,
- HITRATE (percent));
- }
- else
- predict_edge_def (e, predictor, TAKEN);
- }
- }
-
- if (gimple_code (stmt) != GIMPLE_COND)
- return;
- FOR_EACH_EDGE (then_edge, ei, bb->succs)
- if (then_edge->flags & EDGE_TRUE_VALUE)
- break;
- op0 = gimple_cond_lhs (stmt);
- op1 = gimple_cond_rhs (stmt);
- cmp = gimple_cond_code (stmt);
- type = TREE_TYPE (op0);
- val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, auto_bitmap (),
- &predictor, &probability);
- if (val && TREE_CODE (val) == INTEGER_CST)
- {
- HOST_WIDE_INT prob = get_predictor_value (predictor, probability);
- if (integer_zerop (val))
- prob = REG_BR_PROB_BASE - prob;
- predict_edge (then_edge, predictor, prob);
- }
- /* Try "pointer heuristic."
- A comparison ptr == 0 is predicted as false.
- Similarly, a comparison ptr1 == ptr2 is predicted as false. */
- if (POINTER_TYPE_P (type))
- {
- if (cmp == EQ_EXPR)
- predict_edge_def (then_edge, PRED_TREE_POINTER, NOT_TAKEN);
- else if (cmp == NE_EXPR)
- predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN);
- }
- else
-
- /* Try "opcode heuristic."
- EQ tests are usually false and NE tests are usually true. Also,
- most quantities are positive, so we can make the appropriate guesses
- about signed comparisons against zero. */
- switch (cmp)
- {
- case EQ_EXPR:
- case UNEQ_EXPR:
- /* Floating point comparisons appears to behave in a very
- unpredictable way because of special role of = tests in
- FP code. */
- if (FLOAT_TYPE_P (type))
- ;
- /* Comparisons with 0 are often used for booleans and there is
- nothing useful to predict about them. */
- else if (integer_zerop (op0) || integer_zerop (op1))
- ;
- else
- predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, NOT_TAKEN);
- break;
-
- case NE_EXPR:
- case LTGT_EXPR:
- /* Floating point comparisons appears to behave in a very
- unpredictable way because of special role of = tests in
- FP code. */
- if (FLOAT_TYPE_P (type))
- ;
- /* Comparisons with 0 are often used for booleans and there is
- nothing useful to predict about them. */
- else if (integer_zerop (op0)
- || integer_zerop (op1))
- ;
- else
- predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, TAKEN);
- break;
-
- case ORDERED_EXPR:
- predict_edge_def (then_edge, PRED_TREE_FPOPCODE, TAKEN);
- break;
-
- case UNORDERED_EXPR:
- predict_edge_def (then_edge, PRED_TREE_FPOPCODE, NOT_TAKEN);
- break;
-
- case LE_EXPR:
- case LT_EXPR:
- if (integer_zerop (op1)
- || integer_onep (op1)
- || integer_all_onesp (op1)
- || real_zerop (op1)
- || real_onep (op1)
- || real_minus_onep (op1))
- predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, NOT_TAKEN);
- break;
-
- case GE_EXPR:
- case GT_EXPR:
- if (integer_zerop (op1)
- || integer_onep (op1)
- || integer_all_onesp (op1)
- || real_zerop (op1)
- || real_onep (op1)
- || real_minus_onep (op1))
- predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, TAKEN);
- break;
-
- default:
- break;
- }
-}
-
-/* Returns TRUE if the STMT is exit(0) like statement. */
-
-static bool
-is_exit_with_zero_arg (const gimple *stmt)
-{
- /* This is not exit, _exit or _Exit. */
- if (!gimple_call_builtin_p (stmt, BUILT_IN_EXIT)
- && !gimple_call_builtin_p (stmt, BUILT_IN__EXIT)
- && !gimple_call_builtin_p (stmt, BUILT_IN__EXIT2))
- return false;
-
- /* Argument is an interger zero. */
- return integer_zerop (gimple_call_arg (stmt, 0));
-}
-
-/* Try to guess whether the value of return means error code. */
-
-static enum br_predictor
-return_prediction (tree val, enum prediction *prediction)
-{
- /* VOID. */
- if (!val)
- return PRED_NO_PREDICTION;
- /* Different heuristics for pointers and scalars. */
- if (POINTER_TYPE_P (TREE_TYPE (val)))
- {
- /* NULL is usually not returned. */
- if (integer_zerop (val))
- {
- *prediction = NOT_TAKEN;
- return PRED_NULL_RETURN;
- }
- }
- else if (INTEGRAL_TYPE_P (TREE_TYPE (val)))
- {
- /* Negative return values are often used to indicate
- errors. */
- if (TREE_CODE (val) == INTEGER_CST
- && tree_int_cst_sgn (val) < 0)
- {
- *prediction = NOT_TAKEN;
- return PRED_NEGATIVE_RETURN;
- }
- /* Constant return values seems to be commonly taken.
- Zero/one often represent booleans so exclude them from the
- heuristics. */
- if (TREE_CONSTANT (val)
- && (!integer_zerop (val) && !integer_onep (val)))
- {
- *prediction = NOT_TAKEN;
- return PRED_CONST_RETURN;
- }
- }
- return PRED_NO_PREDICTION;
-}
-
-/* Return zero if phi result could have values other than -1, 0 or 1,
- otherwise return a bitmask, with bits 0, 1 and 2 set if -1, 0 and 1
- values are used or likely. */
-
-static int
-zero_one_minusone (gphi *phi, int limit)
-{
- int phi_num_args = gimple_phi_num_args (phi);
- int ret = 0;
- for (int i = 0; i < phi_num_args; i++)
- {
- tree t = PHI_ARG_DEF (phi, i);
- if (TREE_CODE (t) != INTEGER_CST)
- continue;
- wide_int w = wi::to_wide (t);
- if (w == -1)
- ret |= 1;
- else if (w == 0)
- ret |= 2;
- else if (w == 1)
- ret |= 4;
- else
- return 0;
- }
- for (int i = 0; i < phi_num_args; i++)
- {
- tree t = PHI_ARG_DEF (phi, i);
- if (TREE_CODE (t) == INTEGER_CST)
- continue;
- if (TREE_CODE (t) != SSA_NAME)
- return 0;
- gimple *g = SSA_NAME_DEF_STMT (t);
- if (gimple_code (g) == GIMPLE_PHI && limit > 0)
- if (int r = zero_one_minusone (as_a <gphi *> (g), limit - 1))
- {
- ret |= r;
- continue;
- }
- if (!is_gimple_assign (g))
- return 0;
- if (gimple_assign_cast_p (g))
- {
- tree rhs1 = gimple_assign_rhs1 (g);
- if (TREE_CODE (rhs1) != SSA_NAME
- || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
- || TYPE_PRECISION (TREE_TYPE (rhs1)) != 1
- || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
- return 0;
- ret |= (2 | 4);
- continue;
- }
- if (TREE_CODE_CLASS (gimple_assign_rhs_code (g)) != tcc_comparison)
- return 0;
- ret |= (2 | 4);
- }
- return ret;
-}
-
-/* Find the basic block with return expression and look up for possible
- return value trying to apply RETURN_PREDICTION heuristics. */
-static void
-apply_return_prediction (void)
-{
- greturn *return_stmt = NULL;
- tree return_val;
- edge e;
- gphi *phi;
- int phi_num_args, i;
- enum br_predictor pred;
- enum prediction direction;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
- {
- gimple *last = last_stmt (e->src);
- if (last
- && gimple_code (last) == GIMPLE_RETURN)
- {
- return_stmt = as_a <greturn *> (last);
- break;
- }
- }
- if (!e)
- return;
- return_val = gimple_return_retval (return_stmt);
- if (!return_val)
- return;
- if (TREE_CODE (return_val) != SSA_NAME
- || !SSA_NAME_DEF_STMT (return_val)
- || gimple_code (SSA_NAME_DEF_STMT (return_val)) != GIMPLE_PHI)
- return;
- phi = as_a <gphi *> (SSA_NAME_DEF_STMT (return_val));
- phi_num_args = gimple_phi_num_args (phi);
- pred = return_prediction (PHI_ARG_DEF (phi, 0), &direction);
-
- /* Avoid the case where the function returns -1, 0 and 1 values and
- nothing else. Those could be qsort etc. comparison functions
- where the negative return isn't less probable than positive.
- For this require that the function returns at least -1 or 1
- or -1 and a boolean value or comparison result, so that functions
- returning just -1 and 0 are treated as if -1 represents error value. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (return_val))
- && !TYPE_UNSIGNED (TREE_TYPE (return_val))
- && TYPE_PRECISION (TREE_TYPE (return_val)) > 1)
- if (int r = zero_one_minusone (phi, 3))
- if ((r & (1 | 4)) == (1 | 4))
- return;
-
- /* Avoid the degenerate case where all return values form the function
- belongs to same category (ie they are all positive constants)
- so we can hardly say something about them. */
- for (i = 1; i < phi_num_args; i++)
- if (pred != return_prediction (PHI_ARG_DEF (phi, i), &direction))
- break;
- if (i != phi_num_args)
- for (i = 0; i < phi_num_args; i++)
- {
- pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
- if (pred != PRED_NO_PREDICTION)
- predict_paths_leading_to_edge (gimple_phi_arg_edge (phi, i), pred,
- direction);
- }
-}
-
-/* Look for basic block that contains unlikely to happen events
- (such as noreturn calls) and mark all paths leading to execution
- of this basic blocks as unlikely. */
-
-static void
-tree_bb_level_predictions (void)
-{
- basic_block bb;
- bool has_return_edges = false;
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
- if (!unlikely_executed_edge_p (e) && !(e->flags & EDGE_ABNORMAL_CALL))
- {
- has_return_edges = true;
- break;
- }
-
- apply_return_prediction ();
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
- tree decl;
-
- if (is_gimple_call (stmt))
- {
- if (gimple_call_noreturn_p (stmt)
- && has_return_edges
- && !is_exit_with_zero_arg (stmt))
- predict_paths_leading_to (bb, PRED_NORETURN,
- NOT_TAKEN);
- decl = gimple_call_fndecl (stmt);
- if (decl
- && lookup_attribute ("cold",
- DECL_ATTRIBUTES (decl)))
- predict_paths_leading_to (bb, PRED_COLD_FUNCTION,
- NOT_TAKEN);
- if (decl && recursive_call_p (current_function_decl, decl))
- predict_paths_leading_to (bb, PRED_RECURSIVE_CALL,
- NOT_TAKEN);
- }
- else if (gimple_code (stmt) == GIMPLE_PREDICT)
- {
- predict_paths_leading_to (bb, gimple_predict_predictor (stmt),
- gimple_predict_outcome (stmt));
- /* Keep GIMPLE_PREDICT around so early inlining will propagate
- hints to callers. */
- }
- }
- }
-}
-
-/* Callback for hash_map::traverse, asserts that the pointer map is
- empty. */
-
-bool
-assert_is_empty (const_basic_block const &, edge_prediction *const &value,
- void *)
-{
- gcc_assert (!value);
- return true;
-}
-
-/* Predict branch probabilities and estimate profile for basic block BB.
- When LOCAL_ONLY is set do not use any global properties of CFG. */
-
-static void
-tree_estimate_probability_bb (basic_block bb, bool local_only)
-{
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- /* Look for block we are guarding (ie we dominate it,
- but it doesn't postdominate us). */
- if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun) && e->dest != bb
- && !local_only
- && dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
- && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest))
- {
- gimple_stmt_iterator bi;
-
- /* The call heuristic claims that a guarded function call
- is improbable. This is because such calls are often used
- to signal exceptional situations such as printing error
- messages. */
- for (bi = gsi_start_bb (e->dest); !gsi_end_p (bi);
- gsi_next (&bi))
- {
- gimple *stmt = gsi_stmt (bi);
- if (is_gimple_call (stmt)
- && !gimple_inexpensive_call_p (as_a <gcall *> (stmt))
- /* Constant and pure calls are hardly used to signalize
- something exceptional. */
- && gimple_has_side_effects (stmt))
- {
- if (gimple_call_fndecl (stmt))
- predict_edge_def (e, PRED_CALL, NOT_TAKEN);
- else if (virtual_method_call_p (gimple_call_fn (stmt)))
- predict_edge_def (e, PRED_POLYMORPHIC_CALL, NOT_TAKEN);
- else
- predict_edge_def (e, PRED_INDIR_CALL, TAKEN);
- break;
- }
- }
- }
- }
- tree_predict_by_opcode (bb);
-}
-
-/* Predict branch probabilities and estimate profile of the tree CFG.
- This function can be called from the loop optimizers to recompute
- the profile information.
- If DRY_RUN is set, do not modify CFG and only produce dump files. */
-
-void
-tree_estimate_probability (bool dry_run)
-{
- basic_block bb;
-
- connect_infinite_loops_to_exit ();
- /* We use loop_niter_by_eval, which requires that the loops have
- preheaders. */
- create_preheaders (CP_SIMPLE_PREHEADERS);
- calculate_dominance_info (CDI_POST_DOMINATORS);
- /* Decide which edges are known to be unlikely. This improves later
- branch prediction. */
- determine_unlikely_bbs ();
-
- bb_predictions = new hash_map<const_basic_block, edge_prediction *>;
- tree_bb_level_predictions ();
- record_loop_exits ();
-
- if (number_of_loops (cfun) > 1)
- predict_loops ();
-
- FOR_EACH_BB_FN (bb, cfun)
- tree_estimate_probability_bb (bb, false);
-
- FOR_EACH_BB_FN (bb, cfun)
- combine_predictions_for_bb (bb, dry_run);
-
- if (flag_checking)
- bb_predictions->traverse<void *, assert_is_empty> (NULL);
-
- delete bb_predictions;
- bb_predictions = NULL;
-
- if (!dry_run)
- estimate_bb_frequencies (false);
- free_dominance_info (CDI_POST_DOMINATORS);
- remove_fake_exit_edges ();
-}
-
-/* Set edge->probability for each successor edge of BB. */
-void
-tree_guess_outgoing_edge_probabilities (basic_block bb)
-{
- bb_predictions = new hash_map<const_basic_block, edge_prediction *>;
- tree_estimate_probability_bb (bb, true);
- combine_predictions_for_bb (bb, false);
- if (flag_checking)
- bb_predictions->traverse<void *, assert_is_empty> (NULL);
- delete bb_predictions;
- bb_predictions = NULL;
-}
-
-/* Filter function predicate that returns true for a edge predicate P
- if its edge is equal to DATA. */
-
-static bool
-not_loop_guard_equal_edge_p (edge_prediction *p, void *data)
-{
- return p->ep_edge != (edge)data || p->ep_predictor != PRED_LOOP_GUARD;
-}
-
-/* Predict edge E with PRED unless it is already predicted by some predictor
- considered equivalent. */
-
-static void
-maybe_predict_edge (edge e, enum br_predictor pred, enum prediction taken)
-{
- if (edge_predicted_by_p (e, pred, taken))
- return;
- if (pred == PRED_LOOP_GUARD
- && edge_predicted_by_p (e, PRED_LOOP_GUARD_WITH_RECURSION, taken))
- return;
- /* Consider PRED_LOOP_GUARD_WITH_RECURSION superrior to LOOP_GUARD. */
- if (pred == PRED_LOOP_GUARD_WITH_RECURSION)
- {
- edge_prediction **preds = bb_predictions->get (e->src);
- if (preds)
- filter_predictions (preds, not_loop_guard_equal_edge_p, e);
- }
- predict_edge_def (e, pred, taken);
-}
-/* Predict edges to successors of CUR whose sources are not postdominated by
- BB by PRED and recurse to all postdominators. */
-
-static void
-predict_paths_for_bb (basic_block cur, basic_block bb,
- enum br_predictor pred,
- enum prediction taken,
- bitmap visited, class loop *in_loop = NULL)
-{
- edge e;
- edge_iterator ei;
- basic_block son;
-
- /* If we exited the loop or CUR is unconditional in the loop, there is
- nothing to do. */
- if (in_loop
- && (!flow_bb_inside_loop_p (in_loop, cur)
- || dominated_by_p (CDI_DOMINATORS, in_loop->latch, cur)))
- return;
-
- /* We are looking for all edges forming edge cut induced by
- set of all blocks postdominated by BB. */
- FOR_EACH_EDGE (e, ei, cur->preds)
- if (e->src->index >= NUM_FIXED_BLOCKS
- && !dominated_by_p (CDI_POST_DOMINATORS, e->src, bb))
- {
- edge e2;
- edge_iterator ei2;
- bool found = false;
-
- /* Ignore fake edges and eh, we predict them as not taken anyway. */
- if (unlikely_executed_edge_p (e))
- continue;
- gcc_assert (bb == cur || dominated_by_p (CDI_POST_DOMINATORS, cur, bb));
-
- /* See if there is an edge from e->src that is not abnormal
- and does not lead to BB and does not exit the loop. */
- FOR_EACH_EDGE (e2, ei2, e->src->succs)
- if (e2 != e
- && !unlikely_executed_edge_p (e2)
- && !dominated_by_p (CDI_POST_DOMINATORS, e2->dest, bb)
- && (!in_loop || !loop_exit_edge_p (in_loop, e2)))
- {
- found = true;
- break;
- }
-
- /* If there is non-abnormal path leaving e->src, predict edge
- using predictor. Otherwise we need to look for paths
- leading to e->src.
-
- The second may lead to infinite loop in the case we are predicitng
- regions that are only reachable by abnormal edges. We simply
- prevent visiting given BB twice. */
- if (found)
- maybe_predict_edge (e, pred, taken);
- else if (bitmap_set_bit (visited, e->src->index))
- predict_paths_for_bb (e->src, e->src, pred, taken, visited, in_loop);
- }
- for (son = first_dom_son (CDI_POST_DOMINATORS, cur);
- son;
- son = next_dom_son (CDI_POST_DOMINATORS, son))
- predict_paths_for_bb (son, bb, pred, taken, visited, in_loop);
-}
-
-/* Sets branch probabilities according to PREDiction and
- FLAGS. */
-
-static void
-predict_paths_leading_to (basic_block bb, enum br_predictor pred,
- enum prediction taken, class loop *in_loop)
-{
- predict_paths_for_bb (bb, bb, pred, taken, auto_bitmap (), in_loop);
-}
-
-/* Like predict_paths_leading_to but take edge instead of basic block. */
-
-static void
-predict_paths_leading_to_edge (edge e, enum br_predictor pred,
- enum prediction taken, class loop *in_loop)
-{
- bool has_nonloop_edge = false;
- edge_iterator ei;
- edge e2;
-
- basic_block bb = e->src;
- FOR_EACH_EDGE (e2, ei, bb->succs)
- if (e2->dest != e->src && e2->dest != e->dest
- && !unlikely_executed_edge_p (e2)
- && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e2->dest))
- {
- has_nonloop_edge = true;
- break;
- }
-
- if (!has_nonloop_edge)
- predict_paths_for_bb (bb, bb, pred, taken, auto_bitmap (), in_loop);
- else
- maybe_predict_edge (e, pred, taken);
-}
-
-/* This is used to carry information about basic blocks. It is
- attached to the AUX field of the standard CFG block. */
-
-class block_info
-{
-public:
- /* Estimated frequency of execution of basic_block. */
- sreal frequency;
-
- /* To keep queue of basic blocks to process. */
- basic_block next;
-
- /* Number of predecessors we need to visit first. */
- int npredecessors;
-};
-
-/* Similar information for edges. */
-class edge_prob_info
-{
-public:
- /* In case edge is a loopback edge, the probability edge will be reached
- in case header is. Estimated number of iterations of the loop can be
- then computed as 1 / (1 - back_edge_prob). */
- sreal back_edge_prob;
- /* True if the edge is a loopback edge in the natural loop. */
- unsigned int back_edge:1;
-};
-
-#define BLOCK_INFO(B) ((block_info *) (B)->aux)
-#undef EDGE_INFO
-#define EDGE_INFO(E) ((edge_prob_info *) (E)->aux)
-
-/* Helper function for estimate_bb_frequencies.
- Propagate the frequencies in blocks marked in
- TOVISIT, starting in HEAD. */
-
-static void
-propagate_freq (basic_block head, bitmap tovisit,
- sreal max_cyclic_prob)
-{
- basic_block bb;
- basic_block last;
- unsigned i;
- edge e;
- basic_block nextbb;
- bitmap_iterator bi;
-
- /* For each basic block we need to visit count number of his predecessors
- we need to visit first. */
- EXECUTE_IF_SET_IN_BITMAP (tovisit, 0, i, bi)
- {
- edge_iterator ei;
- int count = 0;
-
- bb = BASIC_BLOCK_FOR_FN (cfun, i);
-
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- bool visit = bitmap_bit_p (tovisit, e->src->index);
-
- if (visit && !(e->flags & EDGE_DFS_BACK))
- count++;
- else if (visit && dump_file && !EDGE_INFO (e)->back_edge)
- fprintf (dump_file,
- "Irreducible region hit, ignoring edge to %i->%i\n",
- e->src->index, bb->index);
- }
- BLOCK_INFO (bb)->npredecessors = count;
- /* When function never returns, we will never process exit block. */
- if (!count && bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
- bb->count = profile_count::zero ();
- }
-
- BLOCK_INFO (head)->frequency = 1;
- last = head;
- for (bb = head; bb; bb = nextbb)
- {
- edge_iterator ei;
- sreal cyclic_probability = 0;
- sreal frequency = 0;
-
- nextbb = BLOCK_INFO (bb)->next;
- BLOCK_INFO (bb)->next = NULL;
-
- /* Compute frequency of basic block. */
- if (bb != head)
- {
- if (flag_checking)
- FOR_EACH_EDGE (e, ei, bb->preds)
- gcc_assert (!bitmap_bit_p (tovisit, e->src->index)
- || (e->flags & EDGE_DFS_BACK));
-
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (EDGE_INFO (e)->back_edge)
- cyclic_probability += EDGE_INFO (e)->back_edge_prob;
- else if (!(e->flags & EDGE_DFS_BACK))
- {
- /* FIXME: Graphite is producing edges with no profile. Once
- this is fixed, drop this. */
- sreal tmp = e->probability.initialized_p () ?
- e->probability.to_sreal () : 0;
- frequency += tmp * BLOCK_INFO (e->src)->frequency;
- }
-
- if (cyclic_probability == 0)
- {
- BLOCK_INFO (bb)->frequency = frequency;
- }
- else
- {
- if (cyclic_probability > max_cyclic_prob)
- {
- if (dump_file)
- fprintf (dump_file,
- "cyclic probability of bb %i is %f (capped to %f)"
- "; turning freq %f",
- bb->index, cyclic_probability.to_double (),
- max_cyclic_prob.to_double (),
- frequency.to_double ());
-
- cyclic_probability = max_cyclic_prob;
- }
- else if (dump_file)
- fprintf (dump_file,
- "cyclic probability of bb %i is %f; turning freq %f",
- bb->index, cyclic_probability.to_double (),
- frequency.to_double ());
-
- BLOCK_INFO (bb)->frequency = frequency
- / (sreal (1) - cyclic_probability);
- if (dump_file)
- fprintf (dump_file, " to %f\n",
- BLOCK_INFO (bb)->frequency.to_double ());
- }
- }
-
- bitmap_clear_bit (tovisit, bb->index);
-
- e = find_edge (bb, head);
- if (e)
- {
- /* FIXME: Graphite is producing edges with no profile. Once
- this is fixed, drop this. */
- sreal tmp = e->probability.initialized_p () ?
- e->probability.to_sreal () : 0;
- EDGE_INFO (e)->back_edge_prob = tmp * BLOCK_INFO (bb)->frequency;
- }
-
- /* Propagate to successor blocks. */
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->flags & EDGE_DFS_BACK)
- && BLOCK_INFO (e->dest)->npredecessors)
- {
- BLOCK_INFO (e->dest)->npredecessors--;
- if (!BLOCK_INFO (e->dest)->npredecessors)
- {
- if (!nextbb)
- nextbb = e->dest;
- else
- BLOCK_INFO (last)->next = e->dest;
-
- last = e->dest;
- }
- }
- }
-}
-
-/* Estimate frequencies in loops at same nest level. */
-
-static void
-estimate_loops_at_level (class loop *first_loop, sreal max_cyclic_prob)
-{
- class loop *loop;
-
- for (loop = first_loop; loop; loop = loop->next)
- {
- edge e;
- basic_block *bbs;
- unsigned i;
- auto_bitmap tovisit;
-
- estimate_loops_at_level (loop->inner, max_cyclic_prob);
-
- /* Find current loop back edge and mark it. */
- e = loop_latch_edge (loop);
- EDGE_INFO (e)->back_edge = 1;
-
- bbs = get_loop_body (loop);
- for (i = 0; i < loop->num_nodes; i++)
- bitmap_set_bit (tovisit, bbs[i]->index);
- free (bbs);
- propagate_freq (loop->header, tovisit, max_cyclic_prob);
- }
-}
-
-/* Propagates frequencies through structure of loops. */
-
-static void
-estimate_loops (void)
-{
- auto_bitmap tovisit;
- basic_block bb;
- sreal max_cyclic_prob = (sreal)1
- - (sreal)1 / (param_max_predicted_iterations + 1);
-
- /* Start by estimating the frequencies in the loops. */
- if (number_of_loops (cfun) > 1)
- estimate_loops_at_level (current_loops->tree_root->inner, max_cyclic_prob);
-
- /* Now propagate the frequencies through all the blocks. */
- FOR_ALL_BB_FN (bb, cfun)
- {
- bitmap_set_bit (tovisit, bb->index);
- }
- propagate_freq (ENTRY_BLOCK_PTR_FOR_FN (cfun), tovisit, max_cyclic_prob);
-}
-
-/* Drop the profile for NODE to guessed, and update its frequency based on
- whether it is expected to be hot given the CALL_COUNT. */
-
-static void
-drop_profile (struct cgraph_node *node, profile_count call_count)
-{
- struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
- /* In the case where this was called by another function with a
- dropped profile, call_count will be 0. Since there are no
- non-zero call counts to this function, we don't know for sure
- whether it is hot, and therefore it will be marked normal below. */
- bool hot = maybe_hot_count_p (NULL, call_count);
-
- if (dump_file)
- fprintf (dump_file,
- "Dropping 0 profile for %s. %s based on calls.\n",
- node->dump_name (),
- hot ? "Function is hot" : "Function is normal");
- /* We only expect to miss profiles for functions that are reached
- via non-zero call edges in cases where the function may have
- been linked from another module or library (COMDATs and extern
- templates). See the comments below for handle_missing_profiles.
- Also, only warn in cases where the missing counts exceed the
- number of training runs. In certain cases with an execv followed
- by a no-return call the profile for the no-return call is not
- dumped and there can be a mismatch. */
- if (!DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl)
- && call_count > profile_info->runs)
- {
- if (flag_profile_correction)
- {
- if (dump_file)
- fprintf (dump_file,
- "Missing counts for called function %s\n",
- node->dump_name ());
- }
- else
- warning (0, "Missing counts for called function %s",
- node->dump_name ());
- }
-
- basic_block bb;
- if (opt_for_fn (node->decl, flag_guess_branch_prob))
- {
- bool clear_zeros
- = !ENTRY_BLOCK_PTR_FOR_FN (fn)->count.nonzero_p ();
- FOR_ALL_BB_FN (bb, fn)
- if (clear_zeros || !(bb->count == profile_count::zero ()))
- bb->count = bb->count.guessed_local ();
- fn->cfg->count_max = fn->cfg->count_max.guessed_local ();
- }
- else
- {
- FOR_ALL_BB_FN (bb, fn)
- bb->count = profile_count::uninitialized ();
- fn->cfg->count_max = profile_count::uninitialized ();
- }
-
- struct cgraph_edge *e;
- for (e = node->callees; e; e = e->next_callee)
- e->count = gimple_bb (e->call_stmt)->count;
- for (e = node->indirect_calls; e; e = e->next_callee)
- e->count = gimple_bb (e->call_stmt)->count;
- node->count = ENTRY_BLOCK_PTR_FOR_FN (fn)->count;
-
- profile_status_for_fn (fn)
- = (flag_guess_branch_prob ? PROFILE_GUESSED : PROFILE_ABSENT);
- node->frequency
- = hot ? NODE_FREQUENCY_HOT : NODE_FREQUENCY_NORMAL;
-}
-
-/* In the case of COMDAT routines, multiple object files will contain the same
- function and the linker will select one for the binary. In that case
- all the other copies from the profile instrument binary will be missing
- profile counts. Look for cases where this happened, due to non-zero
- call counts going to 0-count functions, and drop the profile to guessed
- so that we can use the estimated probabilities and avoid optimizing only
- for size.
-
- The other case where the profile may be missing is when the routine
- is not going to be emitted to the object file, e.g. for "extern template"
- class methods. Those will be marked DECL_EXTERNAL. Emit a warning in
- all other cases of non-zero calls to 0-count functions. */
-
-void
-handle_missing_profiles (void)
-{
- const int unlikely_frac = param_unlikely_bb_count_fraction;
- struct cgraph_node *node;
- auto_vec<struct cgraph_node *, 64> worklist;
-
- /* See if 0 count function has non-0 count callers. In this case we
- lost some profile. Drop its function profile to PROFILE_GUESSED. */
- FOR_EACH_DEFINED_FUNCTION (node)
- {
- struct cgraph_edge *e;
- profile_count call_count = profile_count::zero ();
- gcov_type max_tp_first_run = 0;
- struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
-
- if (node->count.ipa ().nonzero_p ())
- continue;
- for (e = node->callers; e; e = e->next_caller)
- if (e->count.ipa ().initialized_p () && e->count.ipa () > 0)
- {
- call_count = call_count + e->count.ipa ();
-
- if (e->caller->tp_first_run > max_tp_first_run)
- max_tp_first_run = e->caller->tp_first_run;
- }
-
- /* If time profile is missing, let assign the maximum that comes from
- caller functions. */
- if (!node->tp_first_run && max_tp_first_run)
- node->tp_first_run = max_tp_first_run + 1;
-
- if (call_count > 0
- && fn && fn->cfg
- && call_count.apply_scale (unlikely_frac, 1) >= profile_info->runs)
- {
- drop_profile (node, call_count);
- worklist.safe_push (node);
- }
- }
-
- /* Propagate the profile dropping to other 0-count COMDATs that are
- potentially called by COMDATs we already dropped the profile on. */
- while (worklist.length () > 0)
- {
- struct cgraph_edge *e;
-
- node = worklist.pop ();
- for (e = node->callees; e; e = e->next_caller)
- {
- struct cgraph_node *callee = e->callee;
- struct function *fn = DECL_STRUCT_FUNCTION (callee->decl);
-
- if (!(e->count.ipa () == profile_count::zero ())
- && callee->count.ipa ().nonzero_p ())
- continue;
- if ((DECL_COMDAT (callee->decl) || DECL_EXTERNAL (callee->decl))
- && fn && fn->cfg
- && profile_status_for_fn (fn) == PROFILE_READ)
- {
- drop_profile (node, profile_count::zero ());
- worklist.safe_push (callee);
- }
- }
- }
-}
-
-/* Convert counts measured by profile driven feedback to frequencies.
- Return nonzero iff there was any nonzero execution count. */
-
-bool
-update_max_bb_count (void)
-{
- profile_count true_count_max = profile_count::uninitialized ();
- basic_block bb;
-
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
- true_count_max = true_count_max.max (bb->count);
-
- cfun->cfg->count_max = true_count_max;
-
- return true_count_max.ipa ().nonzero_p ();
-}
-
-/* Return true if function is likely to be expensive, so there is no point to
- optimize performance of prologue, epilogue or do inlining at the expense
- of code size growth. THRESHOLD is the limit of number of instructions
- function can execute at average to be still considered not expensive. */
-
-bool
-expensive_function_p (int threshold)
-{
- basic_block bb;
-
- /* If profile was scaled in a way entry block has count 0, then the function
- is deifnitly taking a lot of time. */
- if (!ENTRY_BLOCK_PTR_FOR_FN (cfun)->count.nonzero_p ())
- return true;
-
- profile_count limit = ENTRY_BLOCK_PTR_FOR_FN
- (cfun)->count.apply_scale (threshold, 1);
- profile_count sum = profile_count::zero ();
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
-
- if (!bb->count.initialized_p ())
- {
- if (dump_file)
- fprintf (dump_file, "Function is considered expensive because"
- " count of bb %i is not initialized\n", bb->index);
- return true;
- }
-
- FOR_BB_INSNS (bb, insn)
- if (active_insn_p (insn))
- {
- sum += bb->count;
- if (sum > limit)
- return true;
- }
- }
-
- return false;
-}
-
-/* All basic blocks that are reachable only from unlikely basic blocks are
- unlikely. */
-
-void
-propagate_unlikely_bbs_forward (void)
-{
- auto_vec<basic_block, 64> worklist;
- basic_block bb;
- edge_iterator ei;
- edge e;
-
- if (!(ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == profile_count::zero ()))
- {
- ENTRY_BLOCK_PTR_FOR_FN (cfun)->aux = (void *)(size_t) 1;
- worklist.safe_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
- while (worklist.length () > 0)
- {
- bb = worklist.pop ();
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->count () == profile_count::zero ())
- && !(e->dest->count == profile_count::zero ())
- && !e->dest->aux)
- {
- e->dest->aux = (void *)(size_t) 1;
- worklist.safe_push (e->dest);
- }
- }
- }
-
- FOR_ALL_BB_FN (bb, cfun)
- {
- if (!bb->aux)
- {
- if (!(bb->count == profile_count::zero ())
- && (dump_file && (dump_flags & TDF_DETAILS)))
- fprintf (dump_file,
- "Basic block %i is marked unlikely by forward prop\n",
- bb->index);
- bb->count = profile_count::zero ();
- }
- else
- bb->aux = NULL;
- }
-}
-
-/* Determine basic blocks/edges that are known to be unlikely executed and set
- their counters to zero.
- This is done with first identifying obviously unlikely BBs/edges and then
- propagating in both directions. */
-
-static void
-determine_unlikely_bbs ()
-{
- basic_block bb;
- auto_vec<basic_block, 64> worklist;
- edge_iterator ei;
- edge e;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- if (!(bb->count == profile_count::zero ())
- && unlikely_executed_bb_p (bb))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Basic block %i is locally unlikely\n",
- bb->index);
- bb->count = profile_count::zero ();
- }
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->probability == profile_probability::never ())
- && unlikely_executed_edge_p (e))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Edge %i->%i is locally unlikely\n",
- bb->index, e->dest->index);
- e->probability = profile_probability::never ();
- }
-
- gcc_checking_assert (!bb->aux);
- }
- propagate_unlikely_bbs_forward ();
-
- auto_vec<int, 64> nsuccs;
- nsuccs.safe_grow_cleared (last_basic_block_for_fn (cfun), true);
- FOR_ALL_BB_FN (bb, cfun)
- if (!(bb->count == profile_count::zero ())
- && bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
- {
- nsuccs[bb->index] = 0;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->probability == profile_probability::never ())
- && !(e->dest->count == profile_count::zero ()))
- nsuccs[bb->index]++;
- if (!nsuccs[bb->index])
- worklist.safe_push (bb);
- }
- while (worklist.length () > 0)
- {
- bb = worklist.pop ();
- if (bb->count == profile_count::zero ())
- continue;
- if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- {
- bool found = false;
- for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
- !gsi_end_p (gsi); gsi_next (&gsi))
- if (stmt_can_terminate_bb_p (gsi_stmt (gsi))
- /* stmt_can_terminate_bb_p special cases noreturns because it
- assumes that fake edges are created. We want to know that
- noreturn alone does not imply BB to be unlikely. */
- || (is_gimple_call (gsi_stmt (gsi))
- && (gimple_call_flags (gsi_stmt (gsi)) & ECF_NORETURN)))
- {
- found = true;
- break;
- }
- if (found)
- continue;
- }
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file,
- "Basic block %i is marked unlikely by backward prop\n",
- bb->index);
- bb->count = profile_count::zero ();
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (!(e->probability == profile_probability::never ()))
- {
- if (!(e->src->count == profile_count::zero ()))
- {
- gcc_checking_assert (nsuccs[e->src->index] > 0);
- nsuccs[e->src->index]--;
- if (!nsuccs[e->src->index])
- worklist.safe_push (e->src);
- }
- }
- }
- /* Finally all edges from non-0 regions to 0 are unlikely. */
- FOR_ALL_BB_FN (bb, cfun)
- {
- if (!(bb->count == profile_count::zero ()))
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->probability == profile_probability::never ())
- && e->dest->count == profile_count::zero ())
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Edge %i->%i is unlikely because "
- "it enters unlikely block\n",
- bb->index, e->dest->index);
- e->probability = profile_probability::never ();
- }
-
- edge other = NULL;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->probability == profile_probability::never ())
- ;
- else if (other)
- {
- other = NULL;
- break;
- }
- else
- other = e;
- if (other
- && !(other->probability == profile_probability::always ()))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Edge %i->%i is locally likely\n",
- bb->index, other->dest->index);
- other->probability = profile_probability::always ();
- }
- }
- if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == profile_count::zero ())
- cgraph_node::get (current_function_decl)->count = profile_count::zero ();
-}
-
-/* Estimate and propagate basic block frequencies using the given branch
- probabilities. If FORCE is true, the frequencies are used to estimate
- the counts even when there are already non-zero profile counts. */
-
-void
-estimate_bb_frequencies (bool force)
-{
- basic_block bb;
- sreal freq_max;
-
- determine_unlikely_bbs ();
-
- if (force || profile_status_for_fn (cfun) != PROFILE_READ
- || !update_max_bb_count ())
- {
-
- mark_dfs_back_edges ();
-
- single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->probability =
- profile_probability::always ();
-
- /* Set up block info for each basic block. */
- alloc_aux_for_blocks (sizeof (block_info));
- alloc_aux_for_edges (sizeof (edge_prob_info));
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
- {
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- /* FIXME: Graphite is producing edges with no profile. Once
- this is fixed, drop this. */
- if (e->probability.initialized_p ())
- EDGE_INFO (e)->back_edge_prob
- = e->probability.to_sreal ();
- else
- /* back_edge_prob = 0.5 */
- EDGE_INFO (e)->back_edge_prob = sreal (1, -1);
- }
- }
-
- /* First compute frequencies locally for each loop from innermost
- to outermost to examine frequencies for back edges. */
- estimate_loops ();
-
- freq_max = 0;
- FOR_EACH_BB_FN (bb, cfun)
- if (freq_max < BLOCK_INFO (bb)->frequency)
- freq_max = BLOCK_INFO (bb)->frequency;
-
- /* Scaling frequencies up to maximal profile count may result in
- frequent overflows especially when inlining loops.
- Small scalling results in unnecesary precision loss. Stay in
- the half of the (exponential) range. */
- freq_max = (sreal (1) << (profile_count::n_bits / 2)) / freq_max;
- if (freq_max < 16)
- freq_max = 16;
- profile_count ipa_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count.ipa ();
- cfun->cfg->count_max = profile_count::uninitialized ();
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
- {
- sreal tmp = BLOCK_INFO (bb)->frequency;
- if (tmp >= 1)
- {
- gimple_stmt_iterator gsi;
- tree decl;
-
- /* Self recursive calls can not have frequency greater than 1
- or program will never terminate. This will result in an
- inconsistent bb profile but it is better than greatly confusing
- IPA cost metrics. */
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (is_gimple_call (gsi_stmt (gsi))
- && (decl = gimple_call_fndecl (gsi_stmt (gsi))) != NULL
- && recursive_call_p (current_function_decl, decl))
- {
- if (dump_file)
- fprintf (dump_file, "Dropping frequency of recursive call"
- " in bb %i from %f\n", bb->index,
- tmp.to_double ());
- tmp = (sreal)9 / (sreal)10;
- break;
- }
- }
- tmp = tmp * freq_max + sreal (1, -1);
- profile_count count = profile_count::from_gcov_type (tmp.to_int ());
-
- /* If we have profile feedback in which this function was never
- executed, then preserve this info. */
- if (!(bb->count == profile_count::zero ()))
- bb->count = count.guessed_local ().combine_with_ipa_count (ipa_count);
- cfun->cfg->count_max = cfun->cfg->count_max.max (bb->count);
- }
-
- free_aux_for_blocks ();
- free_aux_for_edges ();
- }
- compute_function_frequency ();
-}
-
-/* Decide whether function is hot, cold or unlikely executed. */
-void
-compute_function_frequency (void)
-{
- basic_block bb;
- struct cgraph_node *node = cgraph_node::get (current_function_decl);
-
- if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
- || MAIN_NAME_P (DECL_NAME (current_function_decl)))
- node->only_called_at_startup = true;
- if (DECL_STATIC_DESTRUCTOR (current_function_decl))
- node->only_called_at_exit = true;
-
- if (!ENTRY_BLOCK_PTR_FOR_FN (cfun)->count.ipa_p ())
- {
- int flags = flags_from_decl_or_type (current_function_decl);
- if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl))
- != NULL)
- node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
- else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl))
- != NULL)
- node->frequency = NODE_FREQUENCY_HOT;
- else if (flags & ECF_NORETURN)
- node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
- else if (MAIN_NAME_P (DECL_NAME (current_function_decl)))
- node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
- else if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
- || DECL_STATIC_DESTRUCTOR (current_function_decl))
- node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
- return;
- }
-
- node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
- warn_function_cold (current_function_decl);
- if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count.ipa() == profile_count::zero ())
- return;
- FOR_EACH_BB_FN (bb, cfun)
- {
- if (maybe_hot_bb_p (cfun, bb))
- {
- node->frequency = NODE_FREQUENCY_HOT;
- return;
- }
- if (!probably_never_executed_bb_p (cfun, bb))
- node->frequency = NODE_FREQUENCY_NORMAL;
- }
-}
-
-/* Build PREDICT_EXPR. */
-tree
-build_predict_expr (enum br_predictor predictor, enum prediction taken)
-{
- tree t = build1 (PREDICT_EXPR, void_type_node,
- build_int_cst (integer_type_node, predictor));
- SET_PREDICT_EXPR_OUTCOME (t, taken);
- return t;
-}
-
-const char *
-predictor_name (enum br_predictor predictor)
-{
- return predictor_info[predictor].name;
-}
-
-/* Predict branch probabilities and estimate profile of the tree CFG. */
-
-namespace {
-
-const pass_data pass_data_profile =
-{
- GIMPLE_PASS, /* type */
- "profile_estimate", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_BRANCH_PROB, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_profile : public gimple_opt_pass
-{
-public:
- pass_profile (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_profile, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *) { return flag_guess_branch_prob; }
- virtual unsigned int execute (function *);
-
-}; // class pass_profile
-
-unsigned int
-pass_profile::execute (function *fun)
-{
- unsigned nb_loops;
-
- if (profile_status_for_fn (cfun) == PROFILE_GUESSED)
- return 0;
-
- loop_optimizer_init (LOOPS_NORMAL);
- if (dump_file && (dump_flags & TDF_DETAILS))
- flow_loops_dump (dump_file, NULL, 0);
-
- nb_loops = number_of_loops (fun);
- if (nb_loops > 1)
- scev_initialize ();
-
- tree_estimate_probability (false);
-
- if (nb_loops > 1)
- scev_finalize ();
-
- loop_optimizer_finalize ();
- if (dump_file && (dump_flags & TDF_DETAILS))
- gimple_dump_cfg (dump_file, dump_flags);
- if (profile_status_for_fn (fun) == PROFILE_ABSENT)
- profile_status_for_fn (fun) = PROFILE_GUESSED;
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- for (auto loop : loops_list (cfun, LI_FROM_INNERMOST))
- if (loop->header->count.initialized_p ())
- fprintf (dump_file, "Loop got predicted %d to iterate %i times.\n",
- loop->num,
- (int)expected_loop_iterations_unbounded (loop));
- }
- return 0;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_profile (gcc::context *ctxt)
-{
- return new pass_profile (ctxt);
-}
-
-/* Return true when PRED predictor should be removed after early
- tree passes. Most of the predictors are beneficial to survive
- as early inlining can also distribute then into caller's bodies. */
-
-static bool
-strip_predictor_early (enum br_predictor pred)
-{
- switch (pred)
- {
- case PRED_TREE_EARLY_RETURN:
- return true;
- default:
- return false;
- }
-}
-
-/* Get rid of all builtin_expect calls and GIMPLE_PREDICT statements
- we no longer need. EARLY is set to true when called from early
- optimizations. */
-
-unsigned int
-strip_predict_hints (function *fun, bool early)
-{
- basic_block bb;
- gimple *ass_stmt;
- tree var;
- bool changed = false;
-
- FOR_EACH_BB_FN (bb, fun)
- {
- gimple_stmt_iterator bi;
- for (bi = gsi_start_bb (bb); !gsi_end_p (bi);)
- {
- gimple *stmt = gsi_stmt (bi);
-
- if (gimple_code (stmt) == GIMPLE_PREDICT)
- {
- if (!early
- || strip_predictor_early (gimple_predict_predictor (stmt)))
- {
- gsi_remove (&bi, true);
- changed = true;
- continue;
- }
- }
- else if (is_gimple_call (stmt))
- {
- tree fndecl = gimple_call_fndecl (stmt);
-
- if (!early
- && ((fndecl != NULL_TREE
- && fndecl_built_in_p (fndecl, BUILT_IN_EXPECT)
- && gimple_call_num_args (stmt) == 2)
- || (fndecl != NULL_TREE
- && fndecl_built_in_p (fndecl,
- BUILT_IN_EXPECT_WITH_PROBABILITY)
- && gimple_call_num_args (stmt) == 3)
- || (gimple_call_internal_p (stmt)
- && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT)))
- {
- var = gimple_call_lhs (stmt);
- changed = true;
- if (var)
- {
- ass_stmt
- = gimple_build_assign (var, gimple_call_arg (stmt, 0));
- gsi_replace (&bi, ass_stmt, true);
- }
- else
- {
- gsi_remove (&bi, true);
- continue;
- }
- }
- }
- gsi_next (&bi);
- }
- }
- return changed ? TODO_cleanup_cfg : 0;
-}
-
-namespace {
-
-const pass_data pass_data_strip_predict_hints =
-{
- GIMPLE_PASS, /* type */
- "*strip_predict_hints", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_BRANCH_PROB, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_strip_predict_hints : public gimple_opt_pass
-{
-public:
- pass_strip_predict_hints (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_strip_predict_hints, ctxt)
- {}
-
- /* opt_pass methods: */
- opt_pass * clone () { return new pass_strip_predict_hints (m_ctxt); }
- void set_pass_param (unsigned int n, bool param)
- {
- gcc_assert (n == 0);
- early_p = param;
- }
-
- virtual unsigned int execute (function *);
-
-private:
- bool early_p;
-
-}; // class pass_strip_predict_hints
-
-unsigned int
-pass_strip_predict_hints::execute (function *fun)
-{
- return strip_predict_hints (fun, early_p);
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_strip_predict_hints (gcc::context *ctxt)
-{
- return new pass_strip_predict_hints (ctxt);
-}
-
-/* Rebuild function frequencies. Passes are in general expected to
- maintain profile by hand, however in some cases this is not possible:
- for example when inlining several functions with loops freuqencies might run
- out of scale and thus needs to be recomputed. */
-
-void
-rebuild_frequencies (void)
-{
- timevar_push (TV_REBUILD_FREQUENCIES);
-
- /* When the max bb count in the function is small, there is a higher
- chance that there were truncation errors in the integer scaling
- of counts by inlining and other optimizations. This could lead
- to incorrect classification of code as being cold when it isn't.
- In that case, force the estimation of bb counts/frequencies from the
- branch probabilities, rather than computing frequencies from counts,
- which may also lead to frequencies incorrectly reduced to 0. There
- is less precision in the probabilities, so we only do this for small
- max counts. */
- cfun->cfg->count_max = profile_count::uninitialized ();
- basic_block bb;
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
- cfun->cfg->count_max = cfun->cfg->count_max.max (bb->count);
-
- if (profile_status_for_fn (cfun) == PROFILE_GUESSED)
- {
- loop_optimizer_init (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS);
- connect_infinite_loops_to_exit ();
- estimate_bb_frequencies (true);
- remove_fake_exit_edges ();
- loop_optimizer_finalize ();
- }
- else if (profile_status_for_fn (cfun) == PROFILE_READ)
- update_max_bb_count ();
- else if (profile_status_for_fn (cfun) == PROFILE_ABSENT
- && !flag_guess_branch_prob)
- ;
- else
- gcc_unreachable ();
- timevar_pop (TV_REBUILD_FREQUENCIES);
-}
-
-/* Perform a dry run of the branch prediction pass and report comparsion of
- the predicted and real profile into the dump file. */
-
-void
-report_predictor_hitrates (void)
-{
- unsigned nb_loops;
-
- loop_optimizer_init (LOOPS_NORMAL);
- if (dump_file && (dump_flags & TDF_DETAILS))
- flow_loops_dump (dump_file, NULL, 0);
-
- nb_loops = number_of_loops (cfun);
- if (nb_loops > 1)
- scev_initialize ();
-
- tree_estimate_probability (true);
-
- if (nb_loops > 1)
- scev_finalize ();
-
- loop_optimizer_finalize ();
-}
-
-/* Force edge E to be cold.
- If IMPOSSIBLE is true, for edge to have count and probability 0 otherwise
- keep low probability to represent possible error in a guess. This is used
- i.e. in case we predict loop to likely iterate given number of times but
- we are not 100% sure.
-
- This function locally updates profile without attempt to keep global
- consistency which cannot be reached in full generality without full profile
- rebuild from probabilities alone. Doing so is not necessarily a good idea
- because frequencies and counts may be more realistic then probabilities.
-
- In some cases (such as for elimination of early exits during full loop
- unrolling) the caller can ensure that profile will get consistent
- afterwards. */
-
-void
-force_edge_cold (edge e, bool impossible)
-{
- profile_count count_sum = profile_count::zero ();
- profile_probability prob_sum = profile_probability::never ();
- edge_iterator ei;
- edge e2;
- bool uninitialized_exit = false;
-
- /* When branch probability guesses are not known, then do nothing. */
- if (!impossible && !e->count ().initialized_p ())
- return;
-
- profile_probability goal = (impossible ? profile_probability::never ()
- : profile_probability::very_unlikely ());
-
- /* If edge is already improbably or cold, just return. */
- if (e->probability <= goal
- && (!impossible || e->count () == profile_count::zero ()))
- return;
- FOR_EACH_EDGE (e2, ei, e->src->succs)
- if (e2 != e)
- {
- if (e->flags & EDGE_FAKE)
- continue;
- if (e2->count ().initialized_p ())
- count_sum += e2->count ();
- if (e2->probability.initialized_p ())
- prob_sum += e2->probability;
- else
- uninitialized_exit = true;
- }
-
- /* If we are not guessing profiles but have some other edges out,
- just assume the control flow goes elsewhere. */
- if (uninitialized_exit)
- e->probability = goal;
- /* If there are other edges out of e->src, redistribute probabilitity
- there. */
- else if (prob_sum > profile_probability::never ())
- {
- if (!(e->probability < goal))
- e->probability = goal;
-
- profile_probability prob_comp = prob_sum / e->probability.invert ();
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Making edge %i->%i %s by redistributing "
- "probability to other edges.\n",
- e->src->index, e->dest->index,
- impossible ? "impossible" : "cold");
- FOR_EACH_EDGE (e2, ei, e->src->succs)
- if (e2 != e)
- {
- e2->probability /= prob_comp;
- }
- if (current_ir_type () != IR_GIMPLE
- && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- update_br_prob_note (e->src);
- }
- /* If all edges out of e->src are unlikely, the basic block itself
- is unlikely. */
- else
- {
- if (prob_sum == profile_probability::never ())
- e->probability = profile_probability::always ();
- else
- {
- if (impossible)
- e->probability = profile_probability::never ();
- /* If BB has some edges out that are not impossible, we cannot
- assume that BB itself is. */
- impossible = false;
- }
- if (current_ir_type () != IR_GIMPLE
- && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- update_br_prob_note (e->src);
- if (e->src->count == profile_count::zero ())
- return;
- if (count_sum == profile_count::zero () && impossible)
- {
- bool found = false;
- if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
- ;
- else if (current_ir_type () == IR_GIMPLE)
- for (gimple_stmt_iterator gsi = gsi_start_bb (e->src);
- !gsi_end_p (gsi); gsi_next (&gsi))
- {
- if (stmt_can_terminate_bb_p (gsi_stmt (gsi)))
- {
- found = true;
- break;
- }
- }
- /* FIXME: Implement RTL path. */
- else
- found = true;
- if (!found)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file,
- "Making bb %i impossible and dropping count to 0.\n",
- e->src->index);
- e->src->count = profile_count::zero ();
- FOR_EACH_EDGE (e2, ei, e->src->preds)
- force_edge_cold (e2, impossible);
- return;
- }
- }
-
- /* If we did not adjusting, the source basic block has no likely edeges
- leaving other direction. In that case force that bb cold, too.
- This in general is difficult task to do, but handle special case when
- BB has only one predecestor. This is common case when we are updating
- after loop transforms. */
- if (!(prob_sum > profile_probability::never ())
- && count_sum == profile_count::zero ()
- && single_pred_p (e->src) && e->src->count.to_frequency (cfun)
- > (impossible ? 0 : 1))
- {
- int old_frequency = e->src->count.to_frequency (cfun);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Making bb %i %s.\n", e->src->index,
- impossible ? "impossible" : "cold");
- int new_frequency = MIN (e->src->count.to_frequency (cfun),
- impossible ? 0 : 1);
- if (impossible)
- e->src->count = profile_count::zero ();
- else
- e->src->count = e->count ().apply_scale (new_frequency,
- old_frequency);
- force_edge_cold (single_pred_edge (e->src), impossible);
- }
- else if (dump_file && (dump_flags & TDF_DETAILS)
- && maybe_hot_bb_p (cfun, e->src))
- fprintf (dump_file, "Giving up on making bb %i %s.\n", e->src->index,
- impossible ? "impossible" : "cold");
- }
-}
-
-/* Change E's probability to NEW_E_PROB, redistributing the probabilities
- of other outgoing edges proportionally.
-
- Note that this function does not change the profile counts of any
- basic blocks. The caller must do that instead, using whatever
- information it has about the region that needs updating. */
-
-void
-change_edge_frequency (edge e, profile_probability new_e_prob)
-{
- profile_probability old_e_prob = e->probability;
- profile_probability old_other_prob = old_e_prob.invert ();
- profile_probability new_other_prob = new_e_prob.invert ();
-
- e->probability = new_e_prob;
- profile_probability cumulative_prob = new_e_prob;
-
- unsigned int num_other = EDGE_COUNT (e->src->succs) - 1;
- edge other_e;
- edge_iterator ei;
- FOR_EACH_EDGE (other_e, ei, e->src->succs)
- if (other_e != e)
- {
- num_other -= 1;
- if (num_other == 0)
- /* Ensure that the probabilities add up to 1 without
- rounding error. */
- other_e->probability = cumulative_prob.invert ();
- else
- {
- other_e->probability /= old_other_prob;
- other_e->probability *= new_other_prob;
- cumulative_prob += other_e->probability;
- }
- }
-}
-
-#if CHECKING_P
-
-namespace selftest {
-
-/* Test that value range of predictor values defined in predict.def is
- within range (50, 100]. */
-
-struct branch_predictor
-{
- const char *name;
- int probability;
-};
-
-#define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) { NAME, HITRATE },
-
-static void
-test_prediction_value_range ()
-{
- branch_predictor predictors[] = {
-#include "predict.def"
- { NULL, PROB_UNINITIALIZED }
- };
-
- for (unsigned i = 0; predictors[i].name != NULL; i++)
- {
- if (predictors[i].probability == PROB_UNINITIALIZED)
- continue;
-
- unsigned p = 100 * predictors[i].probability / REG_BR_PROB_BASE;
- ASSERT_TRUE (p >= 50 && p <= 100);
- }
-}
-
-#undef DEF_PREDICTOR
-
-/* Run all of the selfests within this file. */
-
-void
-predict_c_tests ()
-{
- test_prediction_value_range ();
-}
-
-} // namespace selftest
-#endif /* CHECKING_P. */